From cfd4da032c0e51d0712a504f3f07f481c7c3458a Mon Sep 17 00:00:00 2001 From: MilhouseVH Date: Mon, 1 Aug 2016 01:51:04 +0100 Subject: [PATCH] RPi/RPi2: Update kodi support patches --- .../RPi/patches/kodi/kodi-000-backports.patch | 2187 -- .../RPi/patches/kodi/kodi-001-backport.patch | 28422 +--------------- .../patches/kodi/kodi-000-backports.patch | 2187 -- .../RPi2/patches/kodi/kodi-001-backport.patch | 28422 +--------------- tools/RPi/rpi-kodi-rebase.sh | 2 +- 5 files changed, 881 insertions(+), 60339 deletions(-) delete mode 100644 projects/RPi/patches/kodi/kodi-000-backports.patch delete mode 100644 projects/RPi2/patches/kodi/kodi-000-backports.patch diff --git a/projects/RPi/patches/kodi/kodi-000-backports.patch b/projects/RPi/patches/kodi/kodi-000-backports.patch deleted file mode 100644 index e09ca0ff94..0000000000 --- a/projects/RPi/patches/kodi/kodi-000-backports.patch +++ /dev/null @@ -1,2187 +0,0 @@ -From 618094ed6ad5b01165de2111410dafbe4160598c Mon Sep 17 00:00:00 2001 -From: Rainer Hochecker -Date: Tue, 31 May 2016 13:28:48 +0200 -Subject: [PATCH 1/3] VideoPlayer: expose stream player info to GUI - ---- - xbmc/GUIInfoManager.cpp | 60 +++++++ - xbmc/cores/DataCacheCore.cpp | 166 ++++++++++++++++- - xbmc/cores/DataCacheCore.h | 55 +++++- - .../VideoPlayer/DVDCodecs/Audio/DVDAudioCodec.h | 6 +- - .../DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp | 3 +- - .../DVDCodecs/Audio/DVDAudioCodecFFmpeg.h | 4 +- - .../DVDCodecs/Audio/DVDAudioCodecPassthrough.cpp | 9 +- - .../DVDCodecs/Audio/DVDAudioCodecPassthrough.h | 4 +- - .../VideoPlayer/DVDCodecs/DVDFactoryCodec.cpp | 6 +- - xbmc/cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.h | 3 +- - .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 30 +++- - .../DVDCodecs/Video/DVDVideoCodecFFmpeg.h | 1 + - xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp | 6 +- - xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.h | 5 +- - xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp | 19 +- - xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.h | 5 +- - xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.cpp | 4 +- - xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.h | 6 +- - xbmc/cores/VideoPlayer/DVDCodecs/Video/VTB.cpp | 4 +- - xbmc/cores/VideoPlayer/DVDCodecs/Video/VTB.h | 6 +- - xbmc/cores/VideoPlayer/Process/ProcessInfo.cpp | 199 +++++++++++++++++++++ - xbmc/cores/VideoPlayer/Process/ProcessInfo.h | 47 +++++ - xbmc/cores/VideoPlayer/VideoPlayerAudio.cpp | 11 +- - xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp | 5 + - xbmc/cores/omxplayer/OMXPlayerAudio.cpp | 1 + - xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 7 + - xbmc/cores/paplayer/VideoPlayerCodec.cpp | 4 +- - xbmc/cores/paplayer/VideoPlayerCodec.h | 2 + - xbmc/guiinfo/GUIInfoLabels.h | 14 ++ - 29 files changed, 662 insertions(+), 30 deletions(-) - -diff --git a/xbmc/GUIInfoManager.cpp b/xbmc/GUIInfoManager.cpp -index 0d37f1f..ab5cb12 100644 ---- a/xbmc/GUIInfoManager.cpp -+++ b/xbmc/GUIInfoManager.cpp -@@ -2108,6 +2108,22 @@ const infomap videoplayer[] = {{ "title", VIDEOPLAYER_TITLE }, - { "episodename", VIDEOPLAYER_EPISODENAME } - }; - -+const infomap player_process[] = -+{ -+ { "videodecoder", PLAYER_PROCESS_VIDEODECODER }, -+ { "deintmethod", PLAYER_PROCESS_DEINTMETHOD }, -+ { "pixformat", PLAYER_PROCESS_PIXELFORMAT }, -+ { "videowidth", PLAYER_PROCESS_VIDEOWIDTH }, -+ { "videoheight", PLAYER_PROCESS_VIDEOHEIGHT }, -+ { "videofps", PLAYER_PROCESS_VIDEOFPS }, -+ { "videodar", PLAYER_PROCESS_VIDEODAR }, -+ { "videohwdecoder", PLAYER_PROCESS_VIDEOHWDECODER }, -+ { "audiodecoder", PLAYER_PROCESS_AUDIODECODER }, -+ { "audiochannels", PLAYER_PROCESS_AUDIOCHANNELS }, -+ { "audiosamplerate", PLAYER_PROCESS_AUDIOSAMPLERATE }, -+ { "audiobitspersample", PLAYER_PROCESS_AUDIOBITSPERSAMPLE } -+}; -+ - /// \page modules__General__List_of_gui_access - /// \section modules__General__List_of_gui_access_Container Container - /// @{ -@@ -5320,6 +5336,14 @@ int CGUIInfoManager::TranslateSingleString(const std::string &strCondition, bool - return videoplayer[i].val; - } - } -+ else if (cat.name == "player_process") -+ { -+ for (size_t i = 0; i < sizeof(player_process) / sizeof(infomap); i++) -+ { -+ if (prop.name == player_process[i].str) -+ return videoplayer[i].val; -+ } -+ } - else if (cat.name == "slideshow") - { - for (size_t i = 0; i < sizeof(slideshow) / sizeof(infomap); i++) -@@ -5993,6 +6017,27 @@ std::string CGUIInfoManager::GetLabel(int info, int contextWindow, std::string * - strLabel = info.language; - } - break; -+ case PLAYER_PROCESS_VIDEODECODER: -+ strLabel = g_dataCacheCore.GetVideoDecoderName(); -+ break; -+ case PLAYER_PROCESS_DEINTMETHOD: -+ strLabel = g_dataCacheCore.GetVideoDeintMethod(); -+ break; -+ case PLAYER_PROCESS_PIXELFORMAT: -+ strLabel = g_dataCacheCore.GetVideoPixelFormat(); -+ break; -+ case PLAYER_PROCESS_VIDEOFPS: -+ strLabel = StringUtils::FormatNumber(g_dataCacheCore.GetVideoFps()); -+ break; -+ case PLAYER_PROCESS_VIDEODAR: -+ strLabel = StringUtils::FormatNumber(CServiceBroker::GetDataCacheCore().GetVideoDAR()); -+ break; -+ case PLAYER_PROCESS_AUDIODECODER: -+ strLabel = g_dataCacheCore.GetAudioDecoderName(); -+ break; -+ case PLAYER_PROCESS_AUDIOCHANNELS: -+ strLabel = g_dataCacheCore.GetAudioChannels(); -+ break; - case RDS_AUDIO_LANG: - case RDS_CHANNEL_COUNTRY: - case RDS_TITLE: -@@ -6555,6 +6600,18 @@ bool CGUIInfoManager::GetInt(int &value, int info, int contextWindow, const CGUI - case SYSTEM_BATTERY_LEVEL: - value = g_powerManager.BatteryLevel(); - return true; -+ case PLAYER_PROCESS_VIDEOWIDTH: -+ value = g_dataCacheCore.GetVideoWidth(); -+ return true; -+ case PLAYER_PROCESS_VIDEOHEIGHT: -+ value = g_dataCacheCore.GetVideoHeight(); -+ return true; -+ case PLAYER_PROCESS_AUDIOSAMPLERATE: -+ value = g_dataCacheCore.GetAudioSampleRate(); -+ return true; -+ case PLAYER_PROCESS_AUDIOBITSPERSAMPLE: -+ value = g_dataCacheCore.GetAudioBitsPerSampe(); -+ return true; - } - return false; - } -@@ -7090,6 +7147,9 @@ bool CGUIInfoManager::GetBool(int condition1, int contextWindow, const CGUIListI - !m_currentFile->GetPVRRadioRDSInfoTag()->GetSMSStudio().empty() || - !m_currentFile->GetPVRRadioRDSInfoTag()->GetPhoneStudio().empty()); - break; -+ case PLAYER_PROCESS_VIDEOHWDECODER: -+ bReturn = g_dataCacheCore.IsVideoHwDecoder(); -+ break; - default: // default, use integer value different from 0 as true - { - int val; -diff --git a/xbmc/cores/DataCacheCore.cpp b/xbmc/cores/DataCacheCore.cpp -index 68cf2fb..cbb0a4f 100644 ---- a/xbmc/cores/DataCacheCore.cpp -+++ b/xbmc/cores/DataCacheCore.cpp -@@ -19,6 +19,12 @@ - */ - - #include "cores/DataCacheCore.h" -+#include "threads/SingleLock.h" -+ -+CDataCacheCore::CDataCacheCore() -+{ -+ m_hasAVInfoChanges = false; -+} - - bool CDataCacheCore::HasAVInfoChanges() - { -@@ -35,4 +41,162 @@ void CDataCacheCore::SignalVideoInfoChange() - void CDataCacheCore::SignalAudioInfoChange() - { - m_hasAVInfoChanges = true; --} -\ No newline at end of file -+} -+ -+void CDataCacheCore::SetVideoDecoderName(std::string name, bool isHw) -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ m_playerVideoInfo.decoderName = name; -+ m_playerVideoInfo.isHwDecoder = isHw; -+} -+ -+std::string CDataCacheCore::GetVideoDecoderName() -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ return m_playerVideoInfo.decoderName; -+} -+ -+bool CDataCacheCore::IsVideoHwDecoder() -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ return m_playerVideoInfo.isHwDecoder; -+} -+ -+ -+void CDataCacheCore::SetVideoDeintMethod(std::string method) -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ m_playerVideoInfo.deintMethod = method; -+} -+ -+std::string CDataCacheCore::GetVideoDeintMethod() -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ return m_playerVideoInfo.deintMethod; -+} -+ -+void CDataCacheCore::SetVideoPixelFormat(std::string pixFormat) -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ m_playerVideoInfo.pixFormat = pixFormat; -+} -+ -+std::string CDataCacheCore::GetVideoPixelFormat() -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ return m_playerVideoInfo.pixFormat; -+} -+ -+void CDataCacheCore::SetVideoDimensions(int width, int height) -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ m_playerVideoInfo.width = width; -+ m_playerVideoInfo.height = height; -+} -+ -+int CDataCacheCore::GetVideoWidth() -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ return m_playerVideoInfo.width; -+} -+ -+int CDataCacheCore::GetVideoHeight() -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ return m_playerVideoInfo.height; -+} -+ -+void CDataCacheCore::SetVideoFps(float fps) -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ m_playerVideoInfo.fps = fps; -+} -+ -+float CDataCacheCore::GetVideoFps() -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ return m_playerVideoInfo.fps; -+} -+ -+void CDataCacheCore::SetVideoDAR(float dar) -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ m_playerVideoInfo.dar = dar; -+} -+ -+float CDataCacheCore::GetVideoDAR() -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ return m_playerVideoInfo.dar; -+} -+ -+// player audio info -+void CDataCacheCore::SetAudioDecoderName(std::string name) -+{ -+ CSingleLock lock(m_audioPlayerSection); -+ -+ m_playerAudioInfo.decoderName = name; -+} -+ -+std::string CDataCacheCore::GetAudioDecoderName() -+{ -+ CSingleLock lock(m_audioPlayerSection); -+ -+ return m_playerAudioInfo.decoderName; -+} -+ -+void CDataCacheCore::SetAudioChannels(std::string channels) -+{ -+ CSingleLock lock(m_audioPlayerSection); -+ -+ m_playerAudioInfo.channels = channels; -+} -+ -+std::string CDataCacheCore::GetAudioChannels() -+{ -+ CSingleLock lock(m_audioPlayerSection); -+ -+ return m_playerAudioInfo.channels; -+} -+ -+void CDataCacheCore::SetAudioSampleRate(int sampleRate) -+{ -+ CSingleLock lock(m_audioPlayerSection); -+ -+ m_playerAudioInfo.sampleRate = sampleRate; -+} -+ -+int CDataCacheCore::GetAudioSampleRate() -+{ -+ CSingleLock lock(m_audioPlayerSection); -+ -+ return m_playerAudioInfo.sampleRate; -+} -+ -+void CDataCacheCore::SetAudioBitsPerSample(int bitsPerSample) -+{ -+ CSingleLock lock(m_audioPlayerSection); -+ -+ m_playerAudioInfo.bitsPerSample = bitsPerSample; -+} -+ -+int CDataCacheCore::GetAudioBitsPerSampe() -+{ -+ CSingleLock lock(m_audioPlayerSection); -+ -+ return m_playerAudioInfo.bitsPerSample; -+} -diff --git a/xbmc/cores/DataCacheCore.h b/xbmc/cores/DataCacheCore.h -index 0df013d..e16c81f 100644 ---- a/xbmc/cores/DataCacheCore.h -+++ b/xbmc/cores/DataCacheCore.h -@@ -20,15 +20,68 @@ - * - */ - -+#include -+#include -+#include "threads/CriticalSection.h" -+ - class CDataCacheCore - { - public: -+ CDataCacheCore(); - bool HasAVInfoChanges(); - void SignalVideoInfoChange(); - void SignalAudioInfoChange(); - -+ // player video info -+ void SetVideoDecoderName(std::string name, bool isHw); -+ std::string GetVideoDecoderName(); -+ bool IsVideoHwDecoder(); -+ void SetVideoDeintMethod(std::string method); -+ std::string GetVideoDeintMethod(); -+ void SetVideoPixelFormat(std::string pixFormat); -+ std::string GetVideoPixelFormat(); -+ void SetVideoDimensions(int width, int height); -+ int GetVideoWidth(); -+ int GetVideoHeight(); -+ void SetVideoFps(float fps); -+ float GetVideoFps(); -+ void SetVideoDAR(float dar); -+ float GetVideoDAR(); -+ -+ // player audio info -+ void SetAudioDecoderName(std::string name); -+ std::string GetAudioDecoderName(); -+ void SetAudioChannels(std::string channels); -+ std::string GetAudioChannels(); -+ void SetAudioSampleRate(int sampleRate); -+ int GetAudioSampleRate(); -+ void SetAudioBitsPerSample(int bitsPerSample); -+ int GetAudioBitsPerSampe(); -+ - protected: -- volatile bool m_hasAVInfoChanges; -+ std::atomic_bool m_hasAVInfoChanges; -+ -+ CCriticalSection m_videoPlayerSection; -+ struct SPlayerVideoInfo -+ { -+ std::string decoderName; -+ bool isHwDecoder; -+ std::string deintMethod; -+ std::string pixFormat; -+ int width; -+ int height; -+ float fps; -+ float dar; -+ } m_playerVideoInfo; -+ -+ CCriticalSection m_audioPlayerSection; -+ struct SPlayerAudioInfo -+ { -+ std::string decoderName; -+ std::string channels; -+ int sampleRate; -+ int bitsPerSample; -+ } m_playerAudioInfo; - }; - - extern CDataCacheCore g_dataCacheCore; -\ No newline at end of file -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodec.h b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodec.h -index 7e0da61..bb698da 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodec.h -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodec.h -@@ -23,6 +23,7 @@ - #include "system.h" - #include "cores/AudioEngine/Utils/AEAudioFormat.h" - #include "cores/AudioEngine/Utils/AEUtil.h" -+#include "cores/VideoPlayer/Process/ProcessInfo.h" - #include "DVDClock.h" - - -@@ -64,7 +65,7 @@ class CDVDAudioCodec - { - public: - -- CDVDAudioCodec() {} -+ CDVDAudioCodec(CProcessInfo &processInfo) : m_processInfo(processInfo) {} - virtual ~CDVDAudioCodec() {} - - /* -@@ -138,4 +139,7 @@ class CDVDAudioCodec - * should return the ffmpeg profile value - */ - virtual int GetProfile() { return 0; } -+ -+protected: -+ CProcessInfo &m_processInfo; - }; -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp -index a21894e..f5880cc 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp -@@ -35,7 +35,7 @@ extern "C" { - #include "cores/AudioEngine/Utils/AEUtil.h" - #endif - --CDVDAudioCodecFFmpeg::CDVDAudioCodecFFmpeg() : CDVDAudioCodec() -+CDVDAudioCodecFFmpeg::CDVDAudioCodecFFmpeg(CProcessInfo &processInfo) : CDVDAudioCodec(processInfo) - { - m_pCodecContext = NULL; - -@@ -126,6 +126,7 @@ bool CDVDAudioCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options - m_iSampleFormat = AV_SAMPLE_FMT_NONE; - m_matrixEncoding = AV_MATRIX_ENCODING_NONE; - -+ m_processInfo.SetAudioDecoderName(m_pCodecContext->codec->name); - return true; - } - -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.h b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.h -index a15317a..d5760bb 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.h -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.h -@@ -29,10 +29,12 @@ extern "C" { - #include "libswresample/swresample.h" - } - -+class CProcessInfo; -+ - class CDVDAudioCodecFFmpeg : public CDVDAudioCodec - { - public: -- CDVDAudioCodecFFmpeg(); -+ CDVDAudioCodecFFmpeg(CProcessInfo &processInfo); - virtual ~CDVDAudioCodecFFmpeg(); - virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options); - virtual void Dispose(); -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.cpp -index 1fb00e1..8009297 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.cpp -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.cpp -@@ -29,7 +29,8 @@ - - #define TRUEHD_BUF_SIZE 61440 - --CDVDAudioCodecPassthrough::CDVDAudioCodecPassthrough(void) : -+CDVDAudioCodecPassthrough::CDVDAudioCodecPassthrough(CProcessInfo &processInfo) : -+ CDVDAudioCodec(processInfo), - m_buffer(NULL), - m_bufferSize(0), - m_trueHDoffset(0) -@@ -51,22 +52,26 @@ bool CDVDAudioCodecPassthrough::Open(CDVDStreamInfo &hints, CDVDCodecOptions &op - case AV_CODEC_ID_AC3: - format.m_streamInfo.m_type = CAEStreamInfo::STREAM_TYPE_AC3; - format.m_streamInfo.m_sampleRate = hints.samplerate; -+ m_processInfo.SetAudioDecoderName("PT_AC3"); - break; - - case AV_CODEC_ID_EAC3: - format.m_streamInfo.m_type = CAEStreamInfo::STREAM_TYPE_EAC3; - format.m_streamInfo.m_sampleRate = hints.samplerate; -+ m_processInfo.SetAudioDecoderName("PT_EAC3"); - break; - - case AV_CODEC_ID_DTS: - format.m_streamInfo.m_type = CAEStreamInfo::STREAM_TYPE_DTSHD; - format.m_streamInfo.m_sampleRate = hints.samplerate; -+ m_processInfo.SetAudioDecoderName("PT_DTSHD"); - break; - - case AV_CODEC_ID_TRUEHD: - format.m_streamInfo.m_type = CAEStreamInfo::STREAM_TYPE_TRUEHD; - format.m_streamInfo.m_sampleRate = hints.samplerate; - m_trueHDBuffer.reset(new uint8_t[TRUEHD_BUF_SIZE]); -+ m_processInfo.SetAudioDecoderName("PT_TRUEHD"); - break; - - default: -@@ -83,6 +88,8 @@ bool CDVDAudioCodecPassthrough::Open(CDVDStreamInfo &hints, CDVDCodecOptions &op - - // only get the dts core from the parser if we don't support dtsHD - m_parser.SetCoreOnly(true); -+ -+ m_processInfo.SetAudioDecoderName("PT_DTS"); - } - - m_dataSize = 0; -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.h b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.h -index a04e736..4005429 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.h -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.h -@@ -29,10 +29,12 @@ - #include "cores/AudioEngine/Utils/AEStreamInfo.h" - #include "cores/AudioEngine/Utils/AEBitstreamPacker.h" - -+class CProcessInfo; -+ - class CDVDAudioCodecPassthrough : public CDVDAudioCodec - { - public: -- CDVDAudioCodecPassthrough(); -+ CDVDAudioCodecPassthrough(CProcessInfo &processInfo); - virtual ~CDVDAudioCodecPassthrough(); - - virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options); -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.cpp -index bb5bfe0..9717412 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.cpp -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.cpp -@@ -173,7 +173,7 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, CProces - return nullptr;; - } - --CDVDAudioCodec* CDVDFactoryCodec::CreateAudioCodec(CDVDStreamInfo &hint, bool allowpassthrough, bool allowdtshddecode) -+CDVDAudioCodec* CDVDFactoryCodec::CreateAudioCodec(CDVDStreamInfo &hint, CProcessInfo &processInfo, bool allowpassthrough, bool allowdtshddecode) - { - CDVDAudioCodec* pCodec = NULL; - CDVDCodecOptions options; -@@ -184,12 +184,12 @@ CDVDAudioCodec* CDVDFactoryCodec::CreateAudioCodec(CDVDStreamInfo &hint, bool al - // we don't use passthrough if "sync playback to display" is enabled - if (allowpassthrough) - { -- pCodec = OpenCodec(new CDVDAudioCodecPassthrough(), hint, options); -+ pCodec = OpenCodec(new CDVDAudioCodecPassthrough(processInfo), hint, options); - if (pCodec) - return pCodec; - } - -- pCodec = OpenCodec(new CDVDAudioCodecFFmpeg(), hint, options); -+ pCodec = OpenCodec(new CDVDAudioCodecFFmpeg(processInfo), hint, options); - if (pCodec) - return pCodec; - -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.h b/xbmc/cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.h -index 45e794b98..d11c700 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.h -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.h -@@ -41,7 +41,8 @@ class CDVDFactoryCodec - static CDVDVideoCodec* CreateVideoCodec(CDVDStreamInfo &hint, - CProcessInfo &processInfo, - const CRenderInfo &info = CRenderInfo()); -- static CDVDAudioCodec* CreateAudioCodec(CDVDStreamInfo &hint, bool allowpassthrough = true, bool allowdtshddecode = true); -+ static CDVDAudioCodec* CreateAudioCodec(CDVDStreamInfo &hint, CProcessInfo &processInfo, -+ bool allowpassthrough = true, bool allowdtshddecode = true); - static CDVDOverlayCodec* CreateOverlayCodec(CDVDStreamInfo &hint ); - - static CDVDAudioCodec* OpenCodec(CDVDAudioCodec* pCodec, CDVDStreamInfo &hint, CDVDCodecOptions &options ); -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -index 0414d85..967d518 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -@@ -68,6 +68,7 @@ extern "C" { - #include "libavfilter/avfilter.h" - #include "libavfilter/buffersink.h" - #include "libavfilter/buffersrc.h" -+#include "libavutil/pixdesc.h" - } - - enum DecoderState -@@ -88,11 +89,12 @@ enum EFilterFlags { - FILTER_ROTATE = 0x40, //< rotate image according to the codec hints - }; - --enum AVPixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx -- , const AVPixelFormat * fmt ) -+enum AVPixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx, const AVPixelFormat * fmt) - { - CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque; - -+ const char* pixFmtName = av_get_pix_fmt_name(*fmt); -+ - // if frame threading is enabled hw accel is not allowed - if(ctx->m_decoderState != STATE_HW_SINGLE) - { -@@ -122,9 +124,10 @@ enum AVPixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avct - if(VDPAU::CDecoder::IsVDPAUFormat(*cur) && CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_USEVDPAU)) - { - CLog::Log(LOGNOTICE,"CDVDVideoCodecFFmpeg::GetFormat - Creating VDPAU(%ix%i)", avctx->width, avctx->height); -- VDPAU::CDecoder* vdp = new VDPAU::CDecoder(); -+ VDPAU::CDecoder* vdp = new VDPAU::CDecoder(ctx->m_processInfo); - if(vdp->Open(avctx, ctx->m_pCodecContext, *cur, ctx->m_uSurfacesCount)) - { -+ ctx->m_processInfo.SetVideoPixelFormat(pixFmtName ? pixFmtName : ""); - ctx->SetHardware(vdp); - return *cur; - } -@@ -137,9 +140,10 @@ enum AVPixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avct - !ctx->m_hints.dvd && !ctx->m_hints.stills) - { - CLog::Log(LOGNOTICE, "CDVDVideoCodecFFmpeg::GetFormat - Creating DXVA(%ix%i)", avctx->width, avctx->height); -- DXVA::CDecoder* dec = new DXVA::CDecoder(); -+ DXVA::CDecoder* dec = new DXVA::CDecoder(ctx->m_processInfo); - if(dec->Open(avctx, ctx->m_pCodecContext, *cur, ctx->m_uSurfacesCount)) - { -+ ctx->m_processInfo.SetVideoPixelFormat(pixFmtName ? pixFmtName : ""); - ctx->SetHardware(dec); - return *cur; - } -@@ -151,9 +155,10 @@ enum AVPixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avct - // mpeg4 vaapi decoding is disabled - if(*cur == AV_PIX_FMT_VAAPI_VLD && CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_USEVAAPI)) - { -- VAAPI::CDecoder* dec = new VAAPI::CDecoder(); -+ VAAPI::CDecoder* dec = new VAAPI::CDecoder(ctx->m_processInfo); - if(dec->Open(avctx, ctx->m_pCodecContext, *cur, ctx->m_uSurfacesCount) == true) - { -+ ctx->m_processInfo.SetVideoPixelFormat(pixFmtName ? pixFmtName : ""); - ctx->SetHardware(dec); - return *cur; - } -@@ -165,9 +170,10 @@ enum AVPixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avct - #ifdef TARGET_DARWIN - if (*cur == AV_PIX_FMT_VIDEOTOOLBOX && CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_USEVTB)) - { -- VTB::CDecoder* dec = new VTB::CDecoder(); -+ VTB::CDecoder* dec = new VTB::CDecoder(ctx->m_processInfo); - if(dec->Open(avctx, ctx->m_pCodecContext, *cur, ctx->m_uSurfacesCount)) - { -+ ctx->m_processInfo.SetVideoPixelFormat(pixFmtName ? pixFmtName : ""); - ctx->SetHardware(dec); - return *cur; - } -@@ -183,6 +189,7 @@ enum AVPixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avct - ctx->m_pCodecContext->hwaccel_context = (void *)ctx->m_options.m_opaque_pointer; - if(dec->Open(avctx, ctx->m_pCodecContext, *cur, ctx->m_uSurfacesCount)) - { -+ ctx->m_processInfo.SetVideoPixelFormat(pixFmtName ? pixFmtName : ""); - ctx->SetHardware(dec); - return *cur; - } -@@ -193,6 +200,7 @@ enum AVPixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avct - cur++; - } - -+ ctx->m_processInfo.SetVideoPixelFormat(pixFmtName ? pixFmtName : ""); - ctx->m_decoderState = STATE_HW_FAILED; - return avcodec_default_get_format(avctx, fmt); - } -@@ -226,6 +234,7 @@ CDVDVideoCodecFFmpeg::CDVDVideoCodecFFmpeg(CProcessInfo &processInfo) : CDVDVide - m_skippedDeint = 0; - m_droppedFrames = 0; - m_interlaced = false; -+ m_DAR = 1.0; - } - - CDVDVideoCodecFFmpeg::~CDVDVideoCodecFFmpeg() -@@ -385,6 +394,9 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options - } - - UpdateName(); -+ -+ m_processInfo.SetVideoDecoderName(m_name, m_pHardware ? true : false); -+ m_processInfo.SetVideoDimensions(m_pCodecContext->coded_width, m_pCodecContext->coded_height); - return true; - } - -@@ -746,6 +758,12 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(DVDVideoPicture* pDvdVideoPicture) - if (aspect_ratio <= 0.0) - aspect_ratio = (float)pDvdVideoPicture->iWidth / (float)pDvdVideoPicture->iHeight; - -+ if (m_DAR != aspect_ratio) -+ { -+ m_DAR = aspect_ratio; -+ m_processInfo.SetVideoDAR(m_DAR); -+ } -+ - /* XXX: we suppose the screen has a 1.0 pixel ratio */ // CDVDVideo will compensate it. - pDvdVideoPicture->iDisplayHeight = pDvdVideoPicture->iHeight; - pDvdVideoPicture->iDisplayWidth = ((int)RINT(pDvdVideoPicture->iHeight * aspect_ratio)) & -3; -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h -index 4ef2982..20bc1ff 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h -@@ -119,6 +119,7 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec - bool m_requestSkipDeint; - int m_codecControlFlags; - bool m_interlaced; -+ double m_DAR; - CDVDStreamInfo m_hints; - CDVDCodecOptions m_options; - }; -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp -index f8730c5..fb83b42 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp -@@ -29,6 +29,7 @@ - #include - #include - #include -+#include "cores/VideoPlayer/Process/ProcessInfo.h" - #include "cores/VideoPlayer/VideoRenderers/RenderManager.h" - #include "../DVDCodecUtils.h" - #include "DXVA.h" -@@ -689,8 +690,9 @@ CRenderPicture::~CRenderPicture() - // DXVA Decoder - //----------------------------------------------------------------------------- - --CDecoder::CDecoder() -- : m_event(true) -+CDecoder::CDecoder(CProcessInfo& processInfo) -+ : m_event(true), -+ m_processInfo(processInfo) - { - m_event.Set(); - m_state = DXVA_OPEN; -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.h -index ab756f7..2170515 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.h -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.h -@@ -28,6 +28,8 @@ - #include "libavcodec/d3d11va.h" - #include "threads/Event.h" - -+class CProcessInfo; -+ - namespace DXVA { - - #define CHECK(a) \ -@@ -114,7 +116,7 @@ class CDecoder - , public ID3DResource - { - public: -- CDecoder(); -+ CDecoder(CProcessInfo& processInfo); - ~CDecoder(); - - // IHardwareDecoder overrides -@@ -163,6 +165,7 @@ class CDecoder - unsigned int m_surface_alignment; - CCriticalSection m_section; - CEvent m_event; -+ CProcessInfo& m_processInfo; - }; - - }; -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp -index c014ce2..1b4c8e8 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp -@@ -24,6 +24,7 @@ - #include "DVDVideoCodec.h" - #include "cores/VideoPlayer/DVDCodecs/DVDCodecUtils.h" - #include "cores/VideoPlayer/DVDClock.h" -+#include "cores/VideoPlayer/Process/ProcessInfo.h" - #include "utils/log.h" - #include "utils/StringUtils.h" - #include "threads/SingleLock.h" -@@ -444,7 +445,9 @@ bool CVideoSurfaces::HasRefs() - // VAAPI - //----------------------------------------------------------------------------- - --CDecoder::CDecoder() : m_vaapiOutput(&m_inMsgEvent) -+CDecoder::CDecoder(CProcessInfo& processInfo) : -+ m_vaapiOutput(&m_inMsgEvent), -+ m_processInfo(processInfo) - { - m_vaapiConfig.videoSurfaces = &m_videoSurfaces; - -@@ -453,6 +456,7 @@ CDecoder::CDecoder() : m_vaapiOutput(&m_inMsgEvent) - m_vaapiConfig.context = 0; - m_vaapiConfig.contextId = VA_INVALID_ID; - m_vaapiConfig.configId = VA_INVALID_ID; -+ m_vaapiConfig.processInfo = &m_processInfo; - m_avctx = NULL; - m_getBufferError = 0; - } -@@ -2016,6 +2020,7 @@ void COutput::InitCycle() - delete m_pp; - m_pp = NULL; - DropVppProcessedPictures(); -+ m_config.processInfo->SetVideoDeintMethod("unknown"); - } - if (!m_pp) - { -@@ -2034,6 +2039,17 @@ void COutput::InitCycle() - { - m_pp->Init(method); - m_currentDiMethod = method; -+ -+ if (method == VS_INTERLACEMETHOD_DEINTERLACE) -+ m_config.processInfo->SetVideoDeintMethod("yadif"); -+ else if (method == VS_INTERLACEMETHOD_RENDER_BOB) -+ m_config.processInfo->SetVideoDeintMethod("render-bob"); -+ else if (method == VS_INTERLACEMETHOD_VAAPI_BOB) -+ m_config.processInfo->SetVideoDeintMethod("vaapi-bob"); -+ else if (method == VS_INTERLACEMETHOD_VAAPI_MADI) -+ m_config.processInfo->SetVideoDeintMethod("vaapi-madi"); -+ else if (method == VS_INTERLACEMETHOD_VAAPI_MACI) -+ m_config.processInfo->SetVideoDeintMethod("vaapi-maci"); - } - else - { -@@ -2066,6 +2082,7 @@ void COutput::InitCycle() - { - m_pp->Init(method); - m_currentDiMethod = method; -+ m_config.processInfo->SetVideoDeintMethod("none"); - } - else - { -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.h -index cc744c7..08c5dfc 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.h -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.h -@@ -48,6 +48,7 @@ extern "C" { - - using namespace Actor; - -+class CProcessInfo; - - #define FULLHD_WIDTH 1920 - -@@ -125,6 +126,7 @@ struct CVaapiConfig - VAProfile profile; - VAConfigAttrib attrib; - Display *x11dsp; -+ CProcessInfo *processInfo; - }; - - /** -@@ -411,7 +413,7 @@ class CDecoder - - public: - -- CDecoder(); -+ CDecoder(CProcessInfo& processInfo); - virtual ~CDecoder(); - - virtual bool Open (AVCodecContext* avctx, AVCodecContext* mainctx, const enum AVPixelFormat, unsigned int surfaces = 0); -@@ -468,6 +470,7 @@ class CDecoder - - int m_codecControl; - std::vector m_diMethods; -+ CProcessInfo& m_processInfo; - }; - - //----------------------------------------------------------------------------- -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.cpp -index 331b719..377c72b 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.cpp -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.cpp -@@ -25,6 +25,7 @@ - #include "windowing/WindowingFactory.h" - #include "guilib/GraphicContext.h" - #include "guilib/TextureManager.h" -+#include "cores/VideoPlayer/Process/ProcessInfo.h" - #include "cores/VideoPlayer/VideoRenderers/RenderManager.h" - #include "DVDVideoCodecFFmpeg.h" - #include "DVDClock.h" -@@ -467,13 +468,14 @@ int CVideoSurfaces::Size() - // CVDPAU - //----------------------------------------------------------------------------- - --CDecoder::CDecoder() : m_vdpauOutput(&m_inMsgEvent) -+CDecoder::CDecoder(CProcessInfo& processInfo) : m_vdpauOutput(&m_inMsgEvent), m_processInfo(processInfo) - { - m_vdpauConfig.videoSurfaces = &m_videoSurfaces; - - m_vdpauConfigured = false; - m_DisplayState = VDPAU_OPEN; - m_vdpauConfig.context = 0; -+ m_vdpauConfig.processInfo = &m_processInfo; - } - - bool CDecoder::Open(AVCodecContext* avctx, AVCodecContext* mainctx, const enum AVPixelFormat fmt, unsigned int surfaces) -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.h -index 56601a1..59432ad 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.h -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.h -@@ -70,6 +70,8 @@ extern "C" { - #define FULLHD_WIDTH 1920 - #define MAX_PIC_Q_LENGTH 20 //for non-interop_yuv this controls the max length of the decoded pic to render completion Q - -+class CProcessInfo; -+ - namespace VDPAU - { - -@@ -182,6 +184,7 @@ struct CVdpauConfig - uint32_t maxReferences; - bool useInteropYuv; - CVDPAUContext *context; -+ CProcessInfo *processInfo; - }; - - /** -@@ -556,7 +559,7 @@ class CDecoder - uint32_t aux; /* optional extra parameter... */ - }; - -- CDecoder(); -+ CDecoder(CProcessInfo& processInfo); - virtual ~CDecoder(); - - virtual bool Open (AVCodecContext* avctx, AVCodecContext* mainctx, const enum AVPixelFormat, unsigned int surfaces = 0); -@@ -623,6 +626,7 @@ class CDecoder - CVdpauRenderPicture *m_presentPicture; - - int m_codecControl; -+ CProcessInfo& m_processInfo; - }; - - } -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VTB.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VTB.cpp -index 253aefd..287b7c1 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VTB.cpp -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VTB.cpp -@@ -21,6 +21,7 @@ - #ifdef TARGET_DARWIN - #include "platform/darwin/osx/CocoaInterface.h" - #include "platform/darwin/DarwinUtils.h" -+#include "cores/VideoPlayer/Process/ProcessInfo.h" - #include "DVDVideoCodec.h" - #include "DVDCodecs/DVDCodecUtils.h" - #include "utils/log.h" -@@ -34,7 +35,7 @@ extern "C" { - using namespace VTB; - - --CDecoder::CDecoder() -+CDecoder::CDecoder(CProcessInfo& processInfo) : m_processInfo(processInfo) - { - m_avctx = nullptr; - } -@@ -86,6 +87,7 @@ bool CDecoder::Open(AVCodecContext *avctx, AVCodecContext* mainctx, enum AVPixel - mainctx->pix_fmt = fmt; - mainctx->hwaccel_context = avctx->hwaccel_context; - -+ m_processInfo.SetVideoDeintMethod("none"); - return true; - } - -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VTB.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VTB.h -index 1e097d4..bad295b 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VTB.h -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VTB.h -@@ -23,6 +23,8 @@ - - #include "DVDVideoCodecFFmpeg.h" - -+class CProcessInfo; -+ - namespace VTB - { - -@@ -30,7 +32,7 @@ class CDecoder - : public CDVDVideoCodecFFmpeg::IHardwareDecoder - { - public: -- CDecoder(); -+ CDecoder(CProcessInfo& processInfo); - ~CDecoder(); - virtual bool Open(AVCodecContext* avctx, AVCodecContext* mainctx, const enum AVPixelFormat, unsigned int surfaces = 0); - virtual int Decode(AVCodecContext* avctx, AVFrame* frame); -@@ -43,7 +45,7 @@ class CDecoder - protected: - unsigned m_renderbuffers_count; - AVCodecContext *m_avctx; -- -+ CProcessInfo& m_processInfo; - }; - - } -diff --git a/xbmc/cores/VideoPlayer/Process/ProcessInfo.cpp b/xbmc/cores/VideoPlayer/Process/ProcessInfo.cpp -index ceaa256..fc1f5dd 100644 ---- a/xbmc/cores/VideoPlayer/Process/ProcessInfo.cpp -+++ b/xbmc/cores/VideoPlayer/Process/ProcessInfo.cpp -@@ -19,6 +19,8 @@ - */ - - #include "ProcessInfo.h" -+#include "cores/DataCacheCore.h" -+#include "threads/SingleLock.h" - - // Override for platform ports - #if !defined(PLATFORM_OVERRIDE) -@@ -51,3 +53,200 @@ bool CProcessInfo::AllowDTSHDDecode() - { - return true; - } -+ -+void CProcessInfo::ResetVideoCodecInfo() -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ m_videoIsHWDecoder = false; -+ m_videoDecoderName = "unknown"; -+ m_videoDeintMethod = "unknown"; -+ m_videoPixelFormat = "unknown"; -+ m_videoWidth = 0; -+ m_videoHeight = 0; -+ m_videoFPS = 0.0; -+ -+ g_dataCacheCore.SetVideoDecoderName(m_videoDecoderName, m_videoIsHWDecoder); -+ g_dataCacheCore.SetVideoDeintMethod(m_videoDeintMethod); -+ g_dataCacheCore.SetVideoPixelFormat(m_videoPixelFormat); -+ g_dataCacheCore.SetVideoDimensions(m_videoWidth, m_videoHeight); -+ g_dataCacheCore.SetVideoFps(m_videoFPS); -+} -+ -+void CProcessInfo::SetVideoDecoderName(std::string name, bool isHw) -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ m_videoIsHWDecoder = isHw; -+ m_videoDecoderName = name; -+ -+ g_dataCacheCore.SetVideoDecoderName(m_videoDecoderName, m_videoIsHWDecoder); -+} -+ -+std::string CProcessInfo::GetVideoDecoderName() -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ return m_videoDecoderName; -+} -+ -+bool CProcessInfo::IsVideoHwDecoder() -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ return m_videoIsHWDecoder; -+} -+ -+void CProcessInfo::SetVideoDeintMethod(std::string method) -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ m_videoDeintMethod = method; -+ -+ g_dataCacheCore.SetVideoDeintMethod(m_videoDeintMethod); -+} -+ -+std::string CProcessInfo::GetVideoDeintMethod() -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ return m_videoDeintMethod; -+} -+ -+void CProcessInfo::SetVideoPixelFormat(std::string pixFormat) -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ m_videoPixelFormat = pixFormat; -+ -+ g_dataCacheCore.SetVideoPixelFormat(m_videoPixelFormat); -+} -+ -+std::string CProcessInfo::GetVideoPixelFormat() -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ return m_videoPixelFormat; -+} -+ -+void CProcessInfo::SetVideoDimensions(int width, int height) -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ m_videoWidth = width; -+ m_videoHeight = height; -+ -+ g_dataCacheCore.SetVideoDimensions(m_videoWidth, m_videoHeight); -+} -+ -+void CProcessInfo::GetVideoDimensions(int &width, int &height) -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ width = m_videoWidth; -+ height = m_videoHeight; -+} -+ -+void CProcessInfo::SetVideoFps(float fps) -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ m_videoFPS = fps; -+ -+ g_dataCacheCore.SetVideoFps(m_videoFPS); -+} -+ -+float CProcessInfo::GetVideoFps() -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ return m_videoFPS; -+} -+ -+void CProcessInfo::SetVideoDAR(float dar) -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ m_videoDAR = dar; -+ -+ CServiceBroker::GetDataCacheCore().SetVideoDAR(m_videoDAR); -+} -+ -+float CProcessInfo::GetVideoDAR() -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ return m_videoDAR; -+} -+ -+// player audio info -+void CProcessInfo::ResetAudioCodecInfo() -+{ -+ CSingleLock lock(m_audioCodecSection); -+ -+ m_audioDecoderName = "unknown"; -+ m_audioChannels = "unknown"; -+ m_audioSampleRate = 0;; -+ m_audioBitsPerSample = 0; -+ -+ g_dataCacheCore.SetAudioDecoderName(m_audioDecoderName); -+ g_dataCacheCore.SetAudioChannels(m_audioChannels); -+ g_dataCacheCore.SetAudioSampleRate(m_audioSampleRate); -+ g_dataCacheCore.SetAudioBitsPerSample(m_audioBitsPerSample); -+} -+ -+void CProcessInfo::SetAudioDecoderName(std::string name) -+{ -+ CSingleLock lock(m_audioCodecSection); -+ -+ m_audioDecoderName = name; -+} -+ -+std::string CProcessInfo::GetAudioDecoderName() -+{ -+ CSingleLock lock(m_audioCodecSection); -+ -+ return m_audioDecoderName; -+} -+ -+void CProcessInfo::SetAudioChannels(std::string channels) -+{ -+ CSingleLock lock(m_audioCodecSection); -+ -+ m_audioChannels = channels; -+} -+ -+std::string CProcessInfo::GetAudioChannels() -+{ -+ CSingleLock lock(m_audioCodecSection); -+ -+ return m_audioChannels; -+} -+ -+void CProcessInfo::SetAudioSampleRate(int sampleRate) -+{ -+ CSingleLock lock(m_audioCodecSection); -+ -+ m_audioSampleRate = sampleRate; -+} -+ -+int CProcessInfo::GetAudioSampleRate() -+{ -+ CSingleLock lock(m_audioCodecSection); -+ -+ return m_audioSampleRate; -+} -+ -+void CProcessInfo::SetAudioBitsPerSample(int bitsPerSample) -+{ -+ CSingleLock lock(m_audioCodecSection); -+ -+ m_audioBitsPerSample = bitsPerSample; -+} -+ -+int CProcessInfo::GetAudioBitsPerSampe() -+{ -+ CSingleLock lock(m_audioCodecSection); -+ -+ return m_audioBitsPerSample; -+} -diff --git a/xbmc/cores/VideoPlayer/Process/ProcessInfo.h b/xbmc/cores/VideoPlayer/Process/ProcessInfo.h -index b8a4e46..0ec9a2c 100644 ---- a/xbmc/cores/VideoPlayer/Process/ProcessInfo.h -+++ b/xbmc/cores/VideoPlayer/Process/ProcessInfo.h -@@ -20,6 +20,8 @@ - #pragma once - - #include "cores/IPlayer.h" -+#include "threads/CriticalSection.h" -+#include - - class CProcessInfo - { -@@ -29,6 +31,51 @@ class CProcessInfo - virtual EINTERLACEMETHOD GetFallbackDeintMethod(); - virtual bool AllowDTSHDDecode(); - -+ // player video info -+ void ResetVideoCodecInfo(); -+ void SetVideoDecoderName(std::string name, bool isHw); -+ std::string GetVideoDecoderName(); -+ bool IsVideoHwDecoder(); -+ void SetVideoDeintMethod(std::string method); -+ std::string GetVideoDeintMethod(); -+ void SetVideoPixelFormat(std::string pixFormat); -+ std::string GetVideoPixelFormat(); -+ void SetVideoDimensions(int width, int height); -+ void GetVideoDimensions(int &width, int &height); -+ void SetVideoFps(float fps); -+ float GetVideoFps(); -+ void SetVideoDAR(float dar); -+ float GetVideoDAR(); -+ -+ // player audio info -+ void ResetAudioCodecInfo(); -+ void SetAudioDecoderName(std::string name); -+ std::string GetAudioDecoderName(); -+ void SetAudioChannels(std::string channels); -+ std::string GetAudioChannels(); -+ void SetAudioSampleRate(int sampleRate); -+ int GetAudioSampleRate(); -+ void SetAudioBitsPerSample(int bitsPerSample); -+ int GetAudioBitsPerSampe(); -+ - protected: - CProcessInfo(); -+ -+ // player video info -+ bool m_videoIsHWDecoder; -+ std::string m_videoDecoderName; -+ std::string m_videoDeintMethod; -+ std::string m_videoPixelFormat; -+ int m_videoWidth; -+ int m_videoHeight; -+ float m_videoFPS; -+ float m_videoDAR; -+ CCriticalSection m_videoCodecSection; -+ -+ // player audio info -+ std::string m_audioDecoderName; -+ std::string m_audioChannels; -+ int m_audioSampleRate; -+ int m_audioBitsPerSample; -+ CCriticalSection m_audioCodecSection; - }; -diff --git a/xbmc/cores/VideoPlayer/VideoPlayerAudio.cpp b/xbmc/cores/VideoPlayer/VideoPlayerAudio.cpp -index fb1d993..2422815 100644 ---- a/xbmc/cores/VideoPlayer/VideoPlayerAudio.cpp -+++ b/xbmc/cores/VideoPlayer/VideoPlayerAudio.cpp -@@ -90,11 +90,13 @@ CVideoPlayerAudio::~CVideoPlayerAudio() - - bool CVideoPlayerAudio::OpenStream(CDVDStreamInfo &hints) - { -+ m_processInfo.ResetAudioCodecInfo(); -+ - CLog::Log(LOGNOTICE, "Finding audio codec for: %i", hints.codec); - bool allowpassthrough = !CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_USEDISPLAYASCLOCK); - if (hints.realtime) - allowpassthrough = false; -- CDVDAudioCodec* codec = CDVDFactoryCodec::CreateAudioCodec(hints, allowpassthrough, m_processInfo.AllowDTSHDDecode()); -+ CDVDAudioCodec* codec = CDVDFactoryCodec::CreateAudioCodec(hints, m_processInfo, allowpassthrough, m_processInfo.AllowDTSHDDecode()); - if(!codec) - { - CLog::Log(LOGERROR, "Unsupported audio codec"); -@@ -451,6 +453,11 @@ void CVideoPlayerAudio::Process() - - m_streaminfo.channels = audioframe.format.m_channelLayout.Count(); - -+ -+ m_processInfo.SetAudioChannels(audioframe.format.m_channelLayout); -+ m_processInfo.SetAudioSampleRate(audioframe.format.m_sampleRate); -+ m_processInfo.SetAudioBitsPerSample(audioframe.bits_per_sample); -+ - m_messageParent.Put(new CDVDMsg(CDVDMsg::PLAYER_AVCHANGE)); - } - -@@ -595,7 +602,7 @@ bool CVideoPlayerAudio::SwitchCodecIfNeeded() - bool allowpassthrough = !CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_USEDISPLAYASCLOCK); - if (m_streaminfo.realtime) - allowpassthrough = false; -- CDVDAudioCodec *codec = CDVDFactoryCodec::CreateAudioCodec(m_streaminfo, allowpassthrough, m_processInfo.AllowDTSHDDecode()); -+ CDVDAudioCodec *codec = CDVDFactoryCodec::CreateAudioCodec(m_streaminfo, m_processInfo, allowpassthrough, m_processInfo.AllowDTSHDDecode()); - if (!codec || codec->NeedPassthrough() == m_pAudioCodec->NeedPassthrough()) { - // passthrough state has not changed - delete codec; -diff --git a/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp b/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp -index 8e5d33dc..fd260d43 100644 ---- a/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp -+++ b/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp -@@ -120,6 +120,8 @@ double CVideoPlayerVideo::GetOutputDelay() - - bool CVideoPlayerVideo::OpenStream( CDVDStreamInfo &hint ) - { -+ m_processInfo.ResetVideoCodecInfo(); -+ - CRenderInfo info; - info = m_renderManager.GetRenderInfo(); - -@@ -156,11 +158,13 @@ void CVideoPlayerVideo::OpenStream(CDVDStreamInfo &hint, CDVDVideoCodec* codec) - { - m_fFrameRate = DVD_TIME_BASE / CDVDCodecUtils::NormalizeFrameduration((double)DVD_TIME_BASE * hint.fpsscale / hint.fpsrate); - m_bFpsInvalid = false; -+ m_processInfo.SetVideoFps(m_fFrameRate); - } - else - { - m_fFrameRate = 25; - m_bFpsInvalid = true; -+ m_processInfo.SetVideoFps(0); - } - - m_pullupCorrection.ResetVFRDetection(); -@@ -1023,6 +1027,7 @@ void CVideoPlayerVideo::CalcFrameRate() - CLog::Log(LOGDEBUG,"%s framerate was:%f calculated:%f", __FUNCTION__, m_fFrameRate, m_fStableFrameRate / m_iFrameRateCount); - m_fFrameRate = m_fStableFrameRate / m_iFrameRateCount; - m_bFpsInvalid = false; -+ m_processInfo.SetVideoFps(m_fFrameRate); - } - - //reset the stored framerates -diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp -index 50a5b17..6161962 100644 ---- a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp -+++ b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp -@@ -100,6 +100,7 @@ bool OMXPlayerAudio::OpenStream(CDVDStreamInfo &hints) - { - m_bad_state = false; - -+ m_processInfo.ResetAudioCodecInfo(); - COMXAudioCodecOMX *codec = new COMXAudioCodecOMX(); - - if(!codec || !codec->Open(hints)) -diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -index 236f1b3..0ec7f15 100644 ---- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -@@ -515,6 +515,8 @@ bool OMXPlayerVideo::OpenDecoder() - if(!m_av_clock) - return false; - -+ m_processInfo.ResetVideoCodecInfo(); -+ - if (m_hints.fpsrate && m_hints.fpsscale) - m_fFrameRate = DVD_TIME_BASE / CDVDCodecUtils::NormalizeFrameduration((double)DVD_TIME_BASE * m_hints.fpsscale / m_hints.fpsrate); - else -@@ -525,6 +527,8 @@ bool OMXPlayerVideo::OpenDecoder() - CLog::Log(LOGINFO, "OMXPlayerVideo::OpenDecoder : Invalid framerate %d, using forced 25fps and just trust timestamps\n", (int)m_fFrameRate); - m_fFrameRate = 25; - } -+ m_processInfo.SetVideoFps(m_fFrameRate); -+ - // use aspect in stream if available - if (m_hints.forced_aspect) - m_fForcedAspectRatio = m_hints.aspect; -@@ -705,6 +709,9 @@ void OMXPlayerVideo::ResolutionUpdateCallBack(uint32_t width, uint32_t height, f - m_bAllowFullscreen = false; // only allow on first configure - } - -+ m_processInfo.SetVideoDimensions(width, height); -+ m_processInfo.SetVideoAspectRatio(display_aspect); -+ - unsigned int iDisplayWidth = width; - unsigned int iDisplayHeight = height; - -diff --git a/xbmc/cores/paplayer/VideoPlayerCodec.cpp b/xbmc/cores/paplayer/VideoPlayerCodec.cpp -index 9056cf8..32add6c 100644 ---- a/xbmc/cores/paplayer/VideoPlayerCodec.cpp -+++ b/xbmc/cores/paplayer/VideoPlayerCodec.cpp -@@ -46,6 +46,8 @@ VideoPlayerCodec::VideoPlayerCodec() - m_pResampler = NULL; - m_needConvert = false; - m_channels = 0; -+ -+ m_processInfo.reset(CProcessInfo::CreateInstance()); - } - - VideoPlayerCodec::~VideoPlayerCodec() -@@ -165,7 +167,7 @@ bool VideoPlayerCodec::Init(const CFileItem &file, unsigned int filecache) - - CDVDStreamInfo hint(*pStream, true); - -- m_pAudioCodec = CDVDFactoryCodec::CreateAudioCodec(hint); -+ m_pAudioCodec = CDVDFactoryCodec::CreateAudioCodec(hint, *m_processInfo.get()); - if (!m_pAudioCodec) - { - CLog::Log(LOGERROR, "%s: Could not create audio codec", __FUNCTION__); -diff --git a/xbmc/cores/paplayer/VideoPlayerCodec.h b/xbmc/cores/paplayer/VideoPlayerCodec.h -index 81379bd..042f4f7 100644 ---- a/xbmc/cores/paplayer/VideoPlayerCodec.h -+++ b/xbmc/cores/paplayer/VideoPlayerCodec.h -@@ -73,6 +73,8 @@ class VideoPlayerCodec : public ICodec - bool m_needConvert; - AEAudioFormat m_srcFormat; - int m_channels; -+ -+ std::unique_ptr m_processInfo; - }; - - #endif -diff --git a/xbmc/guiinfo/GUIInfoLabels.h b/xbmc/guiinfo/GUIInfoLabels.h -index 27d6bc2..96edafa 100644 ---- a/xbmc/guiinfo/GUIInfoLabels.h -+++ b/xbmc/guiinfo/GUIInfoLabels.h -@@ -562,6 +562,20 @@ - #define RDS_CHANNEL_COUNTRY (RDS_DATA_START + 44) - #define RDS_DATA_END RDS_CHANNEL_COUNTRY - -+#define PLAYER_PROCESS 1500 -+#define PLAYER_PROCESS_VIDEODECODER (PLAYER_PROCESS) -+#define PLAYER_PROCESS_DEINTMETHOD (PLAYER_PROCESS + 1) -+#define PLAYER_PROCESS_PIXELFORMAT (PLAYER_PROCESS + 2) -+#define PLAYER_PROCESS_VIDEOWIDTH (PLAYER_PROCESS + 3) -+#define PLAYER_PROCESS_VIDEOHEIGHT (PLAYER_PROCESS + 4) -+#define PLAYER_PROCESS_VIDEOFPS (PLAYER_PROCESS + 5) -+#define PLAYER_PROCESS_VIDEODAR (PLAYER_PROCESS + 6) -+#define PLAYER_PROCESS_VIDEOHWDECODER (PLAYER_PROCESS + 7) -+#define PLAYER_PROCESS_AUDIODECODER (PLAYER_PROCESS + 8) -+#define PLAYER_PROCESS_AUDIOCHANNELS (PLAYER_PROCESS + 9) -+#define PLAYER_PROCESS_AUDIOSAMPLERATE (PLAYER_PROCESS + 10) -+#define PLAYER_PROCESS_AUDIOBITSPERSAMPLE (PLAYER_PROCESS + 11) -+ - #define WINDOW_PROPERTY 9993 - #define WINDOW_IS_TOPMOST 9994 - #define WINDOW_IS_VISIBLE 9995 - -From 6855680f52c826aa2a2e2684c5607e00a6f8fff1 Mon Sep 17 00:00:00 2001 -From: Rainer Hochecker -Date: Wed, 22 Jun 2016 18:48:10 +0200 -Subject: [PATCH 2/3] remove DataCacheCore from systemGlobals - ---- - xbmc/Application.cpp | 1 + - xbmc/GUIInfoManager.cpp | 24 ++++++++++----------- - xbmc/ServiceBroker.cpp | 5 +++++ - xbmc/ServiceBroker.h | 2 ++ - xbmc/ServiceManager.cpp | 7 +++++++ - xbmc/ServiceManager.h | 3 +++ - xbmc/SystemGlobals.cpp | 4 ---- - xbmc/cores/DataCacheCore.cpp | 6 ++++++ - xbmc/cores/DataCacheCore.h | 5 ++--- - xbmc/cores/VideoPlayer/Process/ProcessInfo.cpp | 29 +++++++++++++------------- - xbmc/cores/VideoPlayer/VideoPlayer.cpp | 14 +++++++------ - xbmc/cores/paplayer/PAPlayer.cpp | 3 ++- - 12 files changed, 63 insertions(+), 40 deletions(-) - -diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp -index cdcf53e..baada48 100644 ---- a/xbmc/Application.cpp -+++ b/xbmc/Application.cpp -@@ -37,6 +37,7 @@ - #include "cores/AudioEngine/AEFactory.h" - #include "cores/AudioEngine/Engines/ActiveAE/AudioDSPAddons/ActiveAEDSP.h" - #include "cores/AudioEngine/Utils/AEUtil.h" -+#include "cores/DataCacheCore.h" - #include "cores/playercorefactory/PlayerCoreFactory.h" - #include "PlayListPlayer.h" - #include "Autorun.h" -diff --git a/xbmc/GUIInfoManager.cpp b/xbmc/GUIInfoManager.cpp -index ab5cb12..7d42106 100644 ---- a/xbmc/GUIInfoManager.cpp -+++ b/xbmc/GUIInfoManager.cpp -@@ -6018,25 +6018,25 @@ std::string CGUIInfoManager::GetLabel(int info, int contextWindow, std::string * - } - break; - case PLAYER_PROCESS_VIDEODECODER: -- strLabel = g_dataCacheCore.GetVideoDecoderName(); -+ strLabel = CServiceBroker::GetDataCacheCore().GetVideoDecoderName(); - break; - case PLAYER_PROCESS_DEINTMETHOD: -- strLabel = g_dataCacheCore.GetVideoDeintMethod(); -+ strLabel = CServiceBroker::GetDataCacheCore().GetVideoDeintMethod(); - break; - case PLAYER_PROCESS_PIXELFORMAT: -- strLabel = g_dataCacheCore.GetVideoPixelFormat(); -+ strLabel = CServiceBroker::GetDataCacheCore().GetVideoPixelFormat(); - break; - case PLAYER_PROCESS_VIDEOFPS: -- strLabel = StringUtils::FormatNumber(g_dataCacheCore.GetVideoFps()); -+ strLabel = StringUtils::FormatNumber(CServiceBroker::GetDataCacheCore().GetVideoFps()); - break; - case PLAYER_PROCESS_VIDEODAR: - strLabel = StringUtils::FormatNumber(CServiceBroker::GetDataCacheCore().GetVideoDAR()); - break; - case PLAYER_PROCESS_AUDIODECODER: -- strLabel = g_dataCacheCore.GetAudioDecoderName(); -+ strLabel = CServiceBroker::GetDataCacheCore().GetAudioDecoderName(); - break; - case PLAYER_PROCESS_AUDIOCHANNELS: -- strLabel = g_dataCacheCore.GetAudioChannels(); -+ strLabel = CServiceBroker::GetDataCacheCore().GetAudioChannels(); - break; - case RDS_AUDIO_LANG: - case RDS_CHANNEL_COUNTRY: -@@ -6601,16 +6601,16 @@ bool CGUIInfoManager::GetInt(int &value, int info, int contextWindow, const CGUI - value = g_powerManager.BatteryLevel(); - return true; - case PLAYER_PROCESS_VIDEOWIDTH: -- value = g_dataCacheCore.GetVideoWidth(); -+ value = CServiceBroker::GetDataCacheCore().GetVideoWidth(); - return true; - case PLAYER_PROCESS_VIDEOHEIGHT: -- value = g_dataCacheCore.GetVideoHeight(); -+ value = CServiceBroker::GetDataCacheCore().GetVideoHeight(); - return true; - case PLAYER_PROCESS_AUDIOSAMPLERATE: -- value = g_dataCacheCore.GetAudioSampleRate(); -+ value = CServiceBroker::GetDataCacheCore().GetAudioSampleRate(); - return true; - case PLAYER_PROCESS_AUDIOBITSPERSAMPLE: -- value = g_dataCacheCore.GetAudioBitsPerSampe(); -+ value = CServiceBroker::GetDataCacheCore().GetAudioBitsPerSampe(); - return true; - } - return false; -@@ -7148,7 +7148,7 @@ bool CGUIInfoManager::GetBool(int condition1, int contextWindow, const CGUIListI - !m_currentFile->GetPVRRadioRDSInfoTag()->GetPhoneStudio().empty()); - break; - case PLAYER_PROCESS_VIDEOHWDECODER: -- bReturn = g_dataCacheCore.IsVideoHwDecoder(); -+ bReturn = CServiceBroker::GetDataCacheCore().IsVideoHwDecoder(); - break; - default: // default, use integer value different from 0 as true - { -@@ -9150,7 +9150,7 @@ void CGUIInfoManager::UpdateAVInfo() - { - if(g_application.m_pPlayer->IsPlaying()) - { -- if (g_dataCacheCore.HasAVInfoChanges()) -+ if (CServiceBroker::GetDataCacheCore().HasAVInfoChanges()) - { - SPlayerVideoStreamInfo video; - SPlayerAudioStreamInfo audio; -diff --git a/xbmc/ServiceBroker.cpp b/xbmc/ServiceBroker.cpp -index fff03c3..dd5c640 100644 ---- a/xbmc/ServiceBroker.cpp -+++ b/xbmc/ServiceBroker.cpp -@@ -50,3 +50,8 @@ ActiveAE::CActiveAEDSP &CServiceBroker::GetADSP() - { - return g_application.m_ServiceManager->GetADSPManager(); - } -+ -+CDataCacheCore &CServiceBroker::GetDataCacheCore() -+{ -+ return g_application.m_ServiceManager->GetDataCacheCore(); -+} -diff --git a/xbmc/ServiceBroker.h b/xbmc/ServiceBroker.h -index 32add30..9f9de19 100644 ---- a/xbmc/ServiceBroker.h -+++ b/xbmc/ServiceBroker.h -@@ -40,6 +40,7 @@ namespace PVR - } - - class XBPython; -+class CDataCacheCore; - - class CServiceBroker - { -@@ -50,4 +51,5 @@ class CServiceBroker - static XBPython &GetXBPython(); - static PVR::CPVRManager &GetPVRManager(); - static ActiveAE::CActiveAEDSP& GetADSP(); -+ static CDataCacheCore& GetDataCacheCore(); - }; -diff --git a/xbmc/ServiceManager.cpp b/xbmc/ServiceManager.cpp -index 3cc188c..4cf4440 100644 ---- a/xbmc/ServiceManager.cpp -+++ b/xbmc/ServiceManager.cpp -@@ -21,6 +21,7 @@ - #include "ServiceManager.h" - #include "addons/BinaryAddonCache.h" - #include "cores/AudioEngine/Engines/ActiveAE/AudioDSPAddons/ActiveAEDSP.h" -+#include "cores/DataCacheCore.h" - #include "utils/log.h" - #include "interfaces/AnnouncementManager.h" - #include "interfaces/generic/ScriptInvocationManager.h" -@@ -49,6 +50,7 @@ bool CServiceManager::Init2() - - m_ADSPManager.reset(new ActiveAE::CActiveAEDSP()); - m_PVRManager.reset(new PVR::CPVRManager()); -+ m_dataCacheCore.reset(new CDataCacheCore()); - - m_binaryAddonCache.reset( new ADDON::CBinaryAddonCache()); - m_binaryAddonCache->Init(); -@@ -104,3 +106,8 @@ ActiveAE::CActiveAEDSP& CServiceManager::GetADSPManager() - { - return *m_ADSPManager; - } -+ -+CDataCacheCore& CServiceManager::GetDataCacheCore() -+{ -+ return *m_dataCacheCore; -+} -\ No newline at end of file -diff --git a/xbmc/ServiceManager.h b/xbmc/ServiceManager.h -index 9b7806f6..5c7a9a8 100644 ---- a/xbmc/ServiceManager.h -+++ b/xbmc/ServiceManager.h -@@ -42,6 +42,7 @@ class CPVRManager; - } - - class XBPython; -+class CDataCacheCore; - - class CServiceManager - { -@@ -56,6 +57,7 @@ class CServiceManager - XBPython& GetXBPython(); - PVR::CPVRManager& GetPVRManager(); - ActiveAE::CActiveAEDSP& GetADSPManager(); -+ CDataCacheCore& GetDataCacheCore(); - - protected: - std::unique_ptr m_addonMgr; -@@ -64,4 +66,5 @@ class CServiceManager - std::unique_ptr m_XBPython; - std::unique_ptr m_PVRManager; - std::unique_ptr m_ADSPManager; -+ std::unique_ptr m_dataCacheCore; - }; -diff --git a/xbmc/SystemGlobals.cpp b/xbmc/SystemGlobals.cpp -index 9354471..3d1cb55 100644 ---- a/xbmc/SystemGlobals.cpp -+++ b/xbmc/SystemGlobals.cpp -@@ -19,7 +19,6 @@ - */ - #include "system.h" - #include "SectionLoader.h" --#include "cores/DataCacheCore.h" - #include "GUILargeTextureManager.h" - #include "guilib/TextureManager.h" - #include "utils/AlarmClock.h" -@@ -71,6 +70,3 @@ std::map CSpecialProtocol::m_pathMap; - #endif - - CZipManager g_ZipManager; -- -- CDataCacheCore g_dataCacheCore; -- -diff --git a/xbmc/cores/DataCacheCore.cpp b/xbmc/cores/DataCacheCore.cpp -index cbb0a4f..43a24f1 100644 ---- a/xbmc/cores/DataCacheCore.cpp -+++ b/xbmc/cores/DataCacheCore.cpp -@@ -20,12 +20,18 @@ - - #include "cores/DataCacheCore.h" - #include "threads/SingleLock.h" -+#include "ServiceBroker.h" - - CDataCacheCore::CDataCacheCore() - { - m_hasAVInfoChanges = false; - } - -+CDataCacheCore& GetInstance() -+{ -+ return CServiceBroker::GetDataCacheCore(); -+} -+ - bool CDataCacheCore::HasAVInfoChanges() - { - bool ret = m_hasAVInfoChanges; -diff --git a/xbmc/cores/DataCacheCore.h b/xbmc/cores/DataCacheCore.h -index e16c81f..646f512 100644 ---- a/xbmc/cores/DataCacheCore.h -+++ b/xbmc/cores/DataCacheCore.h -@@ -28,6 +28,7 @@ class CDataCacheCore - { - public: - CDataCacheCore(); -+ static CDataCacheCore& GetInstance(); - bool HasAVInfoChanges(); - void SignalVideoInfoChange(); - void SignalAudioInfoChange(); -@@ -82,6 +83,4 @@ class CDataCacheCore - int sampleRate; - int bitsPerSample; - } m_playerAudioInfo; --}; -- --extern CDataCacheCore g_dataCacheCore; -\ No newline at end of file -+}; -\ No newline at end of file -diff --git a/xbmc/cores/VideoPlayer/Process/ProcessInfo.cpp b/xbmc/cores/VideoPlayer/Process/ProcessInfo.cpp -index fc1f5dd..bfd7d58 100644 ---- a/xbmc/cores/VideoPlayer/Process/ProcessInfo.cpp -+++ b/xbmc/cores/VideoPlayer/Process/ProcessInfo.cpp -@@ -19,6 +19,7 @@ - */ - - #include "ProcessInfo.h" -+#include "ServiceBroker.h" - #include "cores/DataCacheCore.h" - #include "threads/SingleLock.h" - -@@ -66,11 +67,11 @@ void CProcessInfo::ResetVideoCodecInfo() - m_videoHeight = 0; - m_videoFPS = 0.0; - -- g_dataCacheCore.SetVideoDecoderName(m_videoDecoderName, m_videoIsHWDecoder); -- g_dataCacheCore.SetVideoDeintMethod(m_videoDeintMethod); -- g_dataCacheCore.SetVideoPixelFormat(m_videoPixelFormat); -- g_dataCacheCore.SetVideoDimensions(m_videoWidth, m_videoHeight); -- g_dataCacheCore.SetVideoFps(m_videoFPS); -+ CServiceBroker::GetDataCacheCore().SetVideoDecoderName(m_videoDecoderName, m_videoIsHWDecoder); -+ CServiceBroker::GetDataCacheCore().SetVideoDeintMethod(m_videoDeintMethod); -+ CServiceBroker::GetDataCacheCore().SetVideoPixelFormat(m_videoPixelFormat); -+ CServiceBroker::GetDataCacheCore().SetVideoDimensions(m_videoWidth, m_videoHeight); -+ CServiceBroker::GetDataCacheCore().SetVideoFps(m_videoFPS); - } - - void CProcessInfo::SetVideoDecoderName(std::string name, bool isHw) -@@ -80,7 +81,7 @@ void CProcessInfo::SetVideoDecoderName(std::string name, bool isHw) - m_videoIsHWDecoder = isHw; - m_videoDecoderName = name; - -- g_dataCacheCore.SetVideoDecoderName(m_videoDecoderName, m_videoIsHWDecoder); -+ CServiceBroker::GetDataCacheCore().SetVideoDecoderName(m_videoDecoderName, m_videoIsHWDecoder); - } - - std::string CProcessInfo::GetVideoDecoderName() -@@ -103,7 +104,7 @@ void CProcessInfo::SetVideoDeintMethod(std::string method) - - m_videoDeintMethod = method; - -- g_dataCacheCore.SetVideoDeintMethod(m_videoDeintMethod); -+ CServiceBroker::GetDataCacheCore().SetVideoDeintMethod(m_videoDeintMethod); - } - - std::string CProcessInfo::GetVideoDeintMethod() -@@ -119,7 +120,7 @@ void CProcessInfo::SetVideoPixelFormat(std::string pixFormat) - - m_videoPixelFormat = pixFormat; - -- g_dataCacheCore.SetVideoPixelFormat(m_videoPixelFormat); -+ CServiceBroker::GetDataCacheCore().SetVideoPixelFormat(m_videoPixelFormat); - } - - std::string CProcessInfo::GetVideoPixelFormat() -@@ -136,7 +137,7 @@ void CProcessInfo::SetVideoDimensions(int width, int height) - m_videoWidth = width; - m_videoHeight = height; - -- g_dataCacheCore.SetVideoDimensions(m_videoWidth, m_videoHeight); -+ CServiceBroker::GetDataCacheCore().SetVideoDimensions(m_videoWidth, m_videoHeight); - } - - void CProcessInfo::GetVideoDimensions(int &width, int &height) -@@ -153,7 +154,7 @@ void CProcessInfo::SetVideoFps(float fps) - - m_videoFPS = fps; - -- g_dataCacheCore.SetVideoFps(m_videoFPS); -+ CServiceBroker::GetDataCacheCore().SetVideoFps(m_videoFPS); - } - - float CProcessInfo::GetVideoFps() -@@ -189,10 +190,10 @@ void CProcessInfo::ResetAudioCodecInfo() - m_audioSampleRate = 0;; - m_audioBitsPerSample = 0; - -- g_dataCacheCore.SetAudioDecoderName(m_audioDecoderName); -- g_dataCacheCore.SetAudioChannels(m_audioChannels); -- g_dataCacheCore.SetAudioSampleRate(m_audioSampleRate); -- g_dataCacheCore.SetAudioBitsPerSample(m_audioBitsPerSample); -+ CServiceBroker::GetDataCacheCore().SetAudioDecoderName(m_audioDecoderName); -+ CServiceBroker::GetDataCacheCore().SetAudioChannels(m_audioChannels); -+ CServiceBroker::GetDataCacheCore().SetAudioSampleRate(m_audioSampleRate); -+ CServiceBroker::GetDataCacheCore().SetAudioBitsPerSample(m_audioBitsPerSample); - } - - void CProcessInfo::SetAudioDecoderName(std::string name) -diff --git a/xbmc/cores/VideoPlayer/VideoPlayer.cpp b/xbmc/cores/VideoPlayer/VideoPlayer.cpp -index 9ed9176..5205414 100644 ---- a/xbmc/cores/VideoPlayer/VideoPlayer.cpp -+++ b/xbmc/cores/VideoPlayer/VideoPlayer.cpp -@@ -45,6 +45,7 @@ - #include "guilib/GUIWindowManager.h" - #include "guilib/StereoscopicsManager.h" - #include "Application.h" -+#include "ServiceBroker.h" - #include "messaging/ApplicationMessenger.h" - - #include "DVDDemuxers/DVDDemuxCC.h" -@@ -81,6 +82,7 @@ - #include "cores/omxplayer/OMXHelper.h" - #endif - #include "VideoPlayerAudio.h" -+#include "cores/DataCacheCore.h" - #include "windowing/WindowingFactory.h" - #include "DVDCodecs/DVDCodecUtils.h" - -@@ -545,8 +547,8 @@ void CSelectionStreams::Update(CDVDInputStream* input, CDVDDemux* demuxer, std:: - Update(s); - } - } -- g_dataCacheCore.SignalAudioInfoChange(); -- g_dataCacheCore.SignalVideoInfoChange(); -+ CServiceBroker::GetDataCacheCore().SignalAudioInfoChange(); -+ CServiceBroker::GetDataCacheCore().SignalVideoInfoChange(); - } - - int CSelectionStreams::CountSource(StreamType type, StreamSource source) const -@@ -2872,8 +2874,8 @@ void CVideoPlayer::HandleMessages() - else if (pMsg->IsType(CDVDMsg::PLAYER_AVCHANGE)) - { - UpdateStreamInfos(); -- g_dataCacheCore.SignalAudioInfoChange(); -- g_dataCacheCore.SignalVideoInfoChange(); -+ CServiceBroker::GetDataCacheCore().SignalAudioInfoChange(); -+ CServiceBroker::GetDataCacheCore().SignalVideoInfoChange(); - } - - pMsg->Release(); -@@ -3596,8 +3598,8 @@ bool CVideoPlayer::OpenStream(CCurrentStream& current, int64_t demuxerId, int iS - } - } - -- g_dataCacheCore.SignalAudioInfoChange(); -- g_dataCacheCore.SignalVideoInfoChange(); -+ CServiceBroker::GetDataCacheCore().SignalAudioInfoChange(); -+ CServiceBroker::GetDataCacheCore().SignalVideoInfoChange(); - - return res; - } -diff --git a/xbmc/cores/paplayer/PAPlayer.cpp b/xbmc/cores/paplayer/PAPlayer.cpp -index 17e1cfc..6bd5180 100644 ---- a/xbmc/cores/paplayer/PAPlayer.cpp -+++ b/xbmc/cores/paplayer/PAPlayer.cpp -@@ -21,6 +21,7 @@ - #include "PAPlayer.h" - #include "CodecFactory.h" - #include "FileItem.h" -+#include "ServiceBroker.h" - #include "settings/AdvancedSettings.h" - #include "settings/Settings.h" - #include "music/tags/MusicInfoTag.h" -@@ -1130,7 +1131,7 @@ void PAPlayer::UpdateGUIData(StreamInfo *si) - total -= m_currentStream->m_startOffset; - m_playerGUIData.m_totalTime = total; - -- g_dataCacheCore.SignalAudioInfoChange(); -+ CServiceBroker::GetDataCacheCore().SignalAudioInfoChange(); - } - - void PAPlayer::OnJobComplete(unsigned int jobID, bool success, CJob *job) - -From 0337c933aaf3a438edba894780838f5c1fbb00f5 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Fri, 24 Jun 2016 19:37:32 +0100 -Subject: [PATCH 3/3] rbp: Update to use new processInfo data cache - ---- - .../VideoPlayer/DVDCodecs/Video/MMALCodec.cpp | 19 +++++++++++++++++ - xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp | 3 ++- - xbmc/cores/omxplayer/OMXAudioCodecOMX.h | 4 +++- - xbmc/cores/omxplayer/OMXPlayerAudio.cpp | 24 +++++++++++++++++++--- - xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 10 ++++----- - xbmc/cores/omxplayer/OMXVideo.cpp | 20 +++++++++++++++++- - xbmc/cores/omxplayer/OMXVideo.h | 4 +++- - 7 files changed, 72 insertions(+), 12 deletions(-) - -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -index 3d026cd..51ded6b2 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -@@ -177,6 +177,10 @@ void CMMALVideo::PortSettingsChanged(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *bu - m_decoded_height = m_es_format->es->video.crop.height; - m_decoded_aligned_width = m_es_format->es->video.width; - m_decoded_aligned_height = m_es_format->es->video.height; -+ -+ m_processInfo.SetVideoDimensions(m_decoded_width, m_decoded_height); -+ m_processInfo.SetVideoDAR(m_aspect_ratio); -+ - if (g_advancedSettings.CanLogComponent(LOGVIDEO)) - CLog::Log(LOGDEBUG, "%s::%s format changed: %dx%d (%dx%d) %.2f", CLASSNAME, __func__, m_decoded_width, m_decoded_height, m_decoded_aligned_width, m_decoded_aligned_height, m_aspect_ratio); - } -@@ -360,6 +364,15 @@ bool CMMALVideo::CreateDeinterlace(EINTERLACEMETHOD interlace_method) - bool advanced_deinterlace = interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED || interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED_HALF; - bool half_framerate = interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED_HALF || interlace_method == VS_INTERLACEMETHOD_MMAL_BOB_HALF; - -+ if (advanced_deinterlace && !half_framerate) -+ m_processInfo.SetVideoDeintMethod("adv(x2)"); -+ else if (advanced_deinterlace && half_framerate) -+ m_processInfo.SetVideoDeintMethod("adv(x1)"); -+ else if (!advanced_deinterlace && !half_framerate) -+ m_processInfo.SetVideoDeintMethod("bob(x2)"); -+ else if (!advanced_deinterlace && half_framerate) -+ m_processInfo.SetVideoDeintMethod("bob(x1)"); -+ - MMAL_PARAMETER_IMAGEFX_PARAMETERS_T imfx_param = {{MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS, sizeof(imfx_param)}, - advanced_deinterlace ? MMAL_PARAM_IMAGEFX_DEINTERLACE_ADV : MMAL_PARAM_IMAGEFX_DEINTERLACE_FAST, 4, {3, 0, half_framerate, 1 }}; - -@@ -437,6 +450,8 @@ bool CMMALVideo::DestroyDeinterlace() - if (g_advancedSettings.CanLogComponent(LOGVIDEO)) - CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__); - -+ m_processInfo.SetVideoDeintMethod("none"); -+ - assert(m_deint); - assert(m_dec_output == m_deint->output[0]); - -@@ -526,6 +541,8 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) - if (!CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_USEMMAL) || hints.software) - return false; - -+ m_processInfo.SetVideoDeintMethod("none"); -+ - m_hints = hints; - m_renderer = (CMMALRenderer *)options.m_opaque_pointer; - MMAL_STATUS_T status; -@@ -732,6 +749,8 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) - m_preroll = !m_hints.stills; - m_speed = DVD_PLAYSPEED_NORMAL; - -+ m_processInfo.SetVideoDecoderName(m_pFormatName, true); -+ - return true; - } - -diff --git a/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp b/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp -index 20f706c..d8cef9c 100644 ---- a/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp -+++ b/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp -@@ -33,7 +33,7 @@ - #define AUDIO_DECODE_OUTPUT_BUFFER (32*1024) - static const char rounded_up_channels_shift[] = {0,0,1,2,2,3,3,3,3}; - --COMXAudioCodecOMX::COMXAudioCodecOMX() -+COMXAudioCodecOMX::COMXAudioCodecOMX(CProcessInfo &processInfo) : m_processInfo(processInfo) - { - m_pBufferOutput = NULL; - m_iBufferOutputAlloced = 0; -@@ -134,6 +134,7 @@ bool COMXAudioCodecOMX::Open(CDVDStreamInfo &hints) - - m_iSampleFormat = AV_SAMPLE_FMT_NONE; - m_desiredSampleFormat = m_pCodecContext->sample_fmt == AV_SAMPLE_FMT_S16 ? AV_SAMPLE_FMT_S16 : AV_SAMPLE_FMT_FLTP; -+ m_processInfo.SetAudioDecoderName(m_pCodecContext->codec->name); - return true; - } - -diff --git a/xbmc/cores/omxplayer/OMXAudioCodecOMX.h b/xbmc/cores/omxplayer/OMXAudioCodecOMX.h -index c06a323..3b2a0f3 100644 ---- a/xbmc/cores/omxplayer/OMXAudioCodecOMX.h -+++ b/xbmc/cores/omxplayer/OMXAudioCodecOMX.h -@@ -31,11 +31,12 @@ extern "C" { - - #include "DVDStreamInfo.h" - #include "linux/PlatformDefs.h" -+#include "cores/VideoPlayer/Process/ProcessInfo.h" - - class COMXAudioCodecOMX - { - public: -- COMXAudioCodecOMX(); -+ COMXAudioCodecOMX(CProcessInfo &processInfo); - virtual ~COMXAudioCodecOMX(); - bool Open(CDVDStreamInfo &hints); - void Dispose(); -@@ -52,6 +53,7 @@ class COMXAudioCodecOMX - unsigned int GetFrameSize() { return m_frameSize; } - - protected: -+ CProcessInfo &m_processInfo; - AVCodecContext* m_pCodecContext; - SwrContext* m_pConvert; - enum AVSampleFormat m_iSampleFormat; -diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp -index 6161962..1e5d2b9 100644 ---- a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp -+++ b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp -@@ -43,6 +43,7 @@ - #include "linux/RBP.h" - #include "cores/AudioEngine/AEFactory.h" - #include "cores/DataCacheCore.h" -+#include "ServiceBroker.h" - - #include - #include -@@ -101,7 +102,7 @@ bool OMXPlayerAudio::OpenStream(CDVDStreamInfo &hints) - m_bad_state = false; - - m_processInfo.ResetAudioCodecInfo(); -- COMXAudioCodecOMX *codec = new COMXAudioCodecOMX(); -+ COMXAudioCodecOMX *codec = new COMXAudioCodecOMX(m_processInfo); - - if(!codec || !codec->Open(hints)) - { -@@ -143,7 +144,7 @@ void OMXPlayerAudio::OpenStream(CDVDStreamInfo &hints, COMXAudioCodecOMX *codec) - m_format.m_sampleRate = 0; - m_format.m_channelLayout = 0; - -- g_dataCacheCore.SignalAudioInfoChange(); -+ CServiceBroker::GetDataCacheCore().SignalAudioInfoChange(); - } - - void OMXPlayerAudio::CloseStream(bool bWaitForBuffers) -@@ -188,6 +189,7 @@ bool OMXPlayerAudio::CodecChange() - { - m_hints.channels = m_pAudioCodec->GetChannels(); - m_hints.samplerate = m_pAudioCodec->GetSampleRate(); -+ m_hints.bitspersample = m_pAudioCodec->GetBitsPerSample(); - } - - /* only check bitrate changes on AV_CODEC_ID_DTS, AV_CODEC_ID_AC3, AV_CODEC_ID_EAC3 */ -@@ -204,7 +206,11 @@ bool OMXPlayerAudio::CodecChange() - (!m_passthrough && minor_change) || !m_DecoderOpen) - { - m_hints_current = m_hints; -- g_dataCacheCore.SignalAudioInfoChange(); -+ -+ m_processInfo.SetAudioSampleRate(m_hints.samplerate); -+ m_processInfo.SetAudioBitsPerSample(m_hints.bitspersample); -+ -+ CServiceBroker::GetDataCacheCore().SignalAudioInfoChange(); - return true; - } - -@@ -562,11 +568,23 @@ bool OMXPlayerAudio::OpenDecoder() - - CAEChannelInfo channelMap; - if (m_pAudioCodec && !m_passthrough) -+ { - channelMap = m_pAudioCodec->GetChannelMap(); -+ } - else if (m_passthrough) -+ { - // we just want to get the channel count right to stop OMXAudio.cpp rejecting stream - // the actual layout is not used - channelMap = AE_CH_LAYOUT_5_1; -+ -+ if (m_hints.codec == AV_CODEC_ID_AC3) -+ m_processInfo.SetAudioDecoderName("PT_AC3"); -+ else if (m_hints.codec == AV_CODEC_ID_EAC3) -+ m_processInfo.SetAudioDecoderName("PT_EAC3"); -+ else -+ m_processInfo.SetAudioDecoderName("PT_DTS"); -+ } -+ m_processInfo.SetAudioChannels(channelMap); - bool bAudioRenderOpen = m_omxAudio.Initialize(m_format, m_av_clock, m_hints, channelMap, m_passthrough); - - m_codec_name = ""; -diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -index 0ec7f15..6efd0d5 100644 ---- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -@@ -73,8 +73,7 @@ OMXPlayerVideo::OMXPlayerVideo(OMXClock *av_clock, - : CThread("OMXPlayerVideo") - , IDVDStreamPlayerVideo(processInfo) - , m_messageQueue("video") --, m_omxVideo(renderManager) --, m_codecname("") -+, m_omxVideo(renderManager, processInfo) - , m_messageParent(parent) - , m_renderManager(renderManager) - { -@@ -471,7 +470,7 @@ void OMXPlayerVideo::Process() - - if (m_syncState == IDVDStreamPlayer::SYNC_STARTING && !bRequestDrop && settings_changed) - { -- m_codecname = m_omxVideo.GetDecoderName(); -+ m_processInfo.SetVideoDecoderName(m_omxVideo.GetDecoderName(), true); - m_syncState = IDVDStreamPlayer::SYNC_WAITSYNC; - SStartMsg msg; - msg.player = VideoPlayer_VIDEO; -@@ -548,7 +547,7 @@ bool OMXPlayerVideo::OpenDecoder() - CLog::Log(LOGINFO, "OMXPlayerVideo::OpenDecoder : Video codec %s width %d height %d profile %d fps %f\n", - m_omxVideo.GetDecoderName().c_str() , m_hints.width, m_hints.height, m_hints.profile, m_fFrameRate); - -- m_codecname = m_omxVideo.GetDecoderName(); -+ m_processInfo.SetVideoDecoderName(m_omxVideo.GetDecoderName(), true); - } - - return bVideoDecoderOpen; -@@ -710,7 +709,7 @@ void OMXPlayerVideo::ResolutionUpdateCallBack(uint32_t width, uint32_t height, f - } - - m_processInfo.SetVideoDimensions(width, height); -- m_processInfo.SetVideoAspectRatio(display_aspect); -+ m_processInfo.SetVideoDAR(display_aspect); - - unsigned int iDisplayWidth = width; - unsigned int iDisplayHeight = height; -@@ -722,6 +721,7 @@ void OMXPlayerVideo::ResolutionUpdateCallBack(uint32_t width, uint32_t height, f - iDisplayWidth = (int) (iDisplayHeight * display_aspect); - - m_fFrameRate = DVD_TIME_BASE / CDVDCodecUtils::NormalizeFrameduration((double)DVD_TIME_BASE / framerate); -+ m_processInfo.SetVideoFps(m_fFrameRate); - - CLog::Log(LOGDEBUG,"%s - change configuration. video:%dx%d. framerate: %4.2f. %dx%d format: BYPASS", - __FUNCTION__, video_width, video_height, m_fFrameRate, iDisplayWidth, iDisplayHeight); -diff --git a/xbmc/cores/omxplayer/OMXVideo.cpp b/xbmc/cores/omxplayer/OMXVideo.cpp -index 4c165bf..b2bb0a8 100644 ---- a/xbmc/cores/omxplayer/OMXVideo.cpp -+++ b/xbmc/cores/omxplayer/OMXVideo.cpp -@@ -65,8 +65,9 @@ - - #define MAX_TEXT_LENGTH 1024 - --COMXVideo::COMXVideo(CRenderManager& renderManager) : m_video_codec_name("") -+COMXVideo::COMXVideo(CRenderManager& renderManager, CProcessInfo &processInfo) : m_video_codec_name("") - , m_renderManager(renderManager) -+, m_processInfo(processInfo) - { - m_is_open = false; - m_extradata = NULL; -@@ -244,6 +245,19 @@ bool COMXVideo::PortSettingsChanged(ResolutionUpdateInfo &resinfo) - EINTERLACEMETHOD interlace_method = m_renderManager.AutoInterlaceMethod(CMediaSettings::GetInstance().GetCurrentVideoSettings().m_InterlaceMethod); - bool advanced_deinterlace = interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED || interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED_HALF; - bool half_framerate = interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED_HALF || interlace_method == VS_INTERLACEMETHOD_MMAL_BOB_HALF; -+ -+ if (advanced_deinterlace && !half_framerate) -+ m_processInfo.SetVideoDeintMethod("adv(x2)"); -+ else if (advanced_deinterlace && half_framerate) -+ m_processInfo.SetVideoDeintMethod("adv(x1)"); -+ else if (!advanced_deinterlace && !half_framerate) -+ m_processInfo.SetVideoDeintMethod("bob(x2)"); -+ else if (!advanced_deinterlace && half_framerate) -+ m_processInfo.SetVideoDeintMethod("bob(x1)"); -+ -+ if (!half_framerate) -+ resinfo.framerate *= 2.0f; -+ - if (!advanced_deinterlace) - { - // Image_fx assumed 3 frames of context. simple deinterlace doesn't require this -@@ -280,6 +294,10 @@ bool COMXVideo::PortSettingsChanged(ResolutionUpdateInfo &resinfo) - return false; - } - } -+ else -+ { -+ m_processInfo.SetVideoDeintMethod("none"); -+ } - - if(m_deinterlace) - { -diff --git a/xbmc/cores/omxplayer/OMXVideo.h b/xbmc/cores/omxplayer/OMXVideo.h -index 46e79cb..fd101e7 100644 ---- a/xbmc/cores/omxplayer/OMXVideo.h -+++ b/xbmc/cores/omxplayer/OMXVideo.h -@@ -34,6 +34,7 @@ - #include "threads/CriticalSection.h" - #include "xbmc/rendering/RenderSystem.h" - #include "cores/VideoPlayer/VideoRenderers/RenderManager.h" -+#include "cores/VideoPlayer/Process/ProcessInfo.h" - #include - - #define VIDEO_BUFFERS 60 -@@ -53,7 +54,7 @@ struct ResolutionUpdateInfo { - class COMXVideo - { - public: -- COMXVideo(CRenderManager& renderManager); -+ COMXVideo(CRenderManager& renderManager, CProcessInfo &processInfo); - ~COMXVideo(); - - // Required overrides -@@ -112,6 +113,7 @@ class COMXVideo - OMX_DISPLAYTRANSFORMTYPE m_transform; - bool m_settings_changed; - CRenderManager& m_renderManager; -+ CProcessInfo& m_processInfo; - static bool NaluFormatStartCodes(enum AVCodecID codec, uint8_t *in_extradata, int in_extrasize); - CCriticalSection m_critSection; - }; diff --git a/projects/RPi/patches/kodi/kodi-001-backport.patch b/projects/RPi/patches/kodi/kodi-001-backport.patch index 1f88c2f0db..baba26d40c 100644 --- a/projects/RPi/patches/kodi/kodi-001-backport.patch +++ b/projects/RPi/patches/kodi/kodi-001-backport.patch @@ -1,7 +1,7 @@ -From 1c8dd52e7185c555335c927aa16102e7b758e54d Mon Sep 17 00:00:00 2001 +From 864954f03895aa990ca985273fef53d962ec0cbf Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 5 May 2015 17:27:39 +0100 -Subject: [PATCH 01/67] build: Allow installed links to be overwritten +Subject: [PATCH 01/61] build: Allow installed links to be overwritten --- tools/depends/target/Makefile | 72 +++++++++++++++++++-------------------- @@ -137,10 +137,10 @@ index e5cb842d9f61578efe5df95dfa3a938cf5346663..3ddba3cefb1ca785f7a17c72f42aacbb + [ -f $(ADDON_DEPS_DIR)/lib/libm.so ] || ln -sf /usr/lib/$(HOST)/libm.so $(ADDON_DEPS_DIR)/lib/ -From 9e113927dc8591c51d7cebc3e13d97c5db19f1d4 Mon Sep 17 00:00:00 2001 +From fd2ced63da994a66ab5c060880009f5e9bab652d Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 7 Apr 2014 18:19:32 +0100 -Subject: [PATCH 02/67] [rbp/omxplayer] When opening a stream don't try to +Subject: [PATCH 02/61] [rbp/omxplayer] When opening a stream don't try to update gui so often --- @@ -164,10 +164,10 @@ index 8ea5161637b4e66ddd222859f058521dbc8922b9..811019a39a10acc21b83f0b0c70d5500 dialog->ProcessRenderLoop(false); if (allowCancel && dialog->IsCanceled()) -From 13bfba5171501299fc0d21ef4c5b1407807242e2 Mon Sep 17 00:00:00 2001 +From c8caccf7ae230790e5b81b496d664a331c7fbead Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sat, 8 Mar 2014 15:36:06 +0000 -Subject: [PATCH 03/67] [hifiberry] Hack: force it to be recognised as IEC958 +Subject: [PATCH 03/61] [hifiberry] Hack: force it to be recognised as IEC958 capable to enable passthrough options --- @@ -190,10 +190,10 @@ index 6a9066b2dbe8d505d636b3638c1d35c7c8a698ed..9c6ac5d4cc9bf21b2d48619cc6fb5d27 info.m_displayName.substr(info.m_displayName.size()-5) == " HDMI") { -From c89b8b2588ffc2fb3022bb2debc09648e66f01d1 Mon Sep 17 00:00:00 2001 +From bf2fbaf79191cbfd18b2b6eff7749d1d28cfdc83 Mon Sep 17 00:00:00 2001 From: Ben Avison Date: Thu, 1 May 2014 16:28:39 +0100 -Subject: [PATCH 04/67] Improved file buffering in CArchive +Subject: [PATCH 04/61] Improved file buffering in CArchive Even though memcpy is typically inlined by the compiler into byte/word loads and stores (at least for release builds), the frequency with which 1, 2 and 4 @@ -213,10 +213,10 @@ that are probably not powerful enough to be good targets for XBMC). 1 file changed, 16 insertions(+) diff --git a/xbmc/utils/Archive.h b/xbmc/utils/Archive.h -index 6ed0f8fe37950306bb6ac369082dd024f032ab66..8506d9593de4c913a3c1469cf9cec89475d8dd30 100644 +index 23cac2759fb10d532da56fa75c5528c5589e9010..89d31d4db1afa7340ed8cd51a7a9fa7acce53b3a 100644 --- a/xbmc/utils/Archive.h +++ b/xbmc/utils/Archive.h -@@ -154,9 +154,17 @@ protected: +@@ -155,9 +155,17 @@ protected: * than waiting until we attempt to put more data into an already full buffer */ if (m_BufferRemain > size) { @@ -233,8 +233,8 @@ index 6ed0f8fe37950306bb6ac369082dd024f032ab66..8506d9593de4c913a3c1469cf9cec894 + } return *this; } - else -@@ -171,9 +179,17 @@ protected: + +@@ -170,9 +178,17 @@ protected: /* Note, refilling the buffer is deferred until we know we need to read more from it */ if (m_BufferRemain >= size) { @@ -251,12 +251,12 @@ index 6ed0f8fe37950306bb6ac369082dd024f032ab66..8506d9593de4c913a3c1469cf9cec894 + } return *this; } - else + -From afe3081bcf63939850a753200650570d04ed8aaa Mon Sep 17 00:00:00 2001 +From ccdbbe94567517e4cb3bc3904d99893affa5132d Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 10 Aug 2014 16:45:16 +0100 -Subject: [PATCH 05/67] filesystem: Make support of browsing into archives +Subject: [PATCH 05/61] filesystem: Make support of browsing into archives optional The ability to browse, scan and play content in archives can cause problems on low powered/low memory devices. @@ -275,10 +275,10 @@ We'll let people who don't use archives disable it manually 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po -index f0cfe2bc13ec3f333af83df21d0185448896719b..8860129ce3d4fd3426f6ba65d0c8cb8df18be8b2 100644 +index 26915cb15fdd589d54c11b1582ef18dc71f38bb2..62bd967a284b0b93820ef75bf8d76c3e78ee889d 100644 --- a/addons/resource.language.en_gb/resources/strings.po +++ b/addons/resource.language.en_gb/resources/strings.po -@@ -19131,6 +19131,15 @@ msgstr "" +@@ -19173,6 +19173,15 @@ msgstr "" #: system/settings/rbp.xml msgctxt "#38010" msgid "GPU accelerated" @@ -295,7 +295,7 @@ index f0cfe2bc13ec3f333af83df21d0185448896719b..8860129ce3d4fd3426f6ba65d0c8cb8d #. Setting #38011 "Show All Items entry" diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml -index 806eadf44d73cea70fdbd8b723770a7f828e0633..7e6e52f82fde4c91fdc004c4b4b46e86091bcc87 100644 +index 265f3982ceee40ece6e3c5073a0e92902f482212..cf15fcbdb860608b2658b310614e1cd78cc94a18 100644 --- a/system/settings/rbp.xml +++ b/system/settings/rbp.xml @@ -99,4 +99,15 @@ @@ -315,10 +315,10 @@ index 806eadf44d73cea70fdbd8b723770a7f828e0633..7e6e52f82fde4c91fdc004c4b4b46e86 + diff --git a/xbmc/Util.cpp b/xbmc/Util.cpp -index b0de1c8f1046e094191f19ecd52334ddc6d1b4d1..446d8df2993423a2f80d88f82fbb7f767b11cf1b 100644 +index f1754ef7343daebd51e6bc892b49fd5c1773cd73..b73ecebb203b11e2e7f1bdc8731fafbaf7f070fa 100644 --- a/xbmc/Util.cpp +++ b/xbmc/Util.cpp -@@ -1773,7 +1773,7 @@ void CUtil::ScanPathsForAssociatedItems(const std::string& videoName, +@@ -1778,7 +1778,7 @@ void CUtil::ScanPathsForAssociatedItems(const std::string& videoName, URIUtils::RemoveExtension(strCandidate); if (StringUtils::StartsWithNoCase(strCandidate, videoName)) { @@ -327,7 +327,7 @@ index b0de1c8f1046e094191f19ecd52334ddc6d1b4d1..446d8df2993423a2f80d88f82fbb7f76 CUtil::ScanArchiveForAssociatedItems(pItem->GetPath(), "", item_exts, associatedFiles); else { -@@ -1783,7 +1783,7 @@ void CUtil::ScanPathsForAssociatedItems(const std::string& videoName, +@@ -1788,7 +1788,7 @@ void CUtil::ScanPathsForAssociatedItems(const std::string& videoName, } else { @@ -366,10 +366,10 @@ index a0fd0a9011e71f4af1535110c696b6ea5c4b37db..688b71a297c7c617c6764bfe6be157d7 { CURL xbtUrl = URIUtils::CreateArchivePath("xbt", url); -From b38f7abd72691bb2eb87892e6619a7eba7ebea77 Mon Sep 17 00:00:00 2001 +From d6eca1347e4e38394f6016def44d98a8fcb0fe61 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 27 Oct 2014 13:06:57 +0000 -Subject: [PATCH 06/67] [rbp] Make cachemembuffersize default depend on memory +Subject: [PATCH 06/61] [rbp] Make cachemembuffersize default depend on memory size --- @@ -379,7 +379,7 @@ Subject: [PATCH 06/67] [rbp] Make cachemembuffersize default depend on memory 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp -index d101638cc38468c3d9673bc48f6603d414bcb7f5..ddbe27061f8192b7f6c830a4c22652a731537079 100644 +index c417308c210204847f9b2d54250af68f2e4e2ee7..6b06c253644a85ca6a5088b07ca41369e38f21d0 100644 --- a/xbmc/linux/RBP.cpp +++ b/xbmc/linux/RBP.cpp @@ -23,6 +23,7 @@ @@ -433,7 +433,7 @@ index a35a509a91483f13e2cf0e688fc7e9528f254290..fffa5182126159f6dfcf750b21fa0464 void Deinitialize(); int GetArmMem() { return m_arm_mem; } diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp -index e7f13a73e5ce6d5fe9864fe76dccc9d3e1fdbc27..446293308010f3b8cd8d325fa6d0285fcc9f892d 100644 +index 6beebe0c9c11b0bab63e5abbd4aea2d62bb05f0c..03f566d3ee4eab690d2236b7739080269d552511 100644 --- a/xbmc/settings/AdvancedSettings.cpp +++ b/xbmc/settings/AdvancedSettings.cpp @@ -50,6 +50,9 @@ @@ -446,7 +446,7 @@ index e7f13a73e5ce6d5fe9864fe76dccc9d3e1fdbc27..446293308010f3b8cd8d325fa6d0285f using namespace ADDON; using namespace XFILE; -@@ -356,7 +359,12 @@ void CAdvancedSettings::Initialize() +@@ -355,7 +358,12 @@ void CAdvancedSettings::Initialize() m_bPVRAutoScanIconsUserSet = false; m_iPVRNumericChannelSwitchTimeout = 1000; @@ -459,7 +459,7 @@ index e7f13a73e5ce6d5fe9864fe76dccc9d3e1fdbc27..446293308010f3b8cd8d325fa6d0285f m_cacheBufferMode = CACHE_BUFFER_MODE_INTERNET; // Default (buffer all internet streams/filesystems) // the following setting determines the readRate of a player data // as multiply of the default data read rate -@@ -405,7 +413,9 @@ void CAdvancedSettings::Initialize() +@@ -404,7 +412,9 @@ void CAdvancedSettings::Initialize() m_extraLogLevels = 0; m_userAgent = g_sysinfo.GetUserAgent(); @@ -471,10 +471,10 @@ index e7f13a73e5ce6d5fe9864fe76dccc9d3e1fdbc27..446293308010f3b8cd8d325fa6d0285f } -From 444ff3630cfa2ff69f1f41150158175ed7d8a549 Mon Sep 17 00:00:00 2001 +From 76c3457a5abf0177d379ed4054938bb73379cc4d Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 30 May 2014 14:58:43 +0100 -Subject: [PATCH 07/67] [settings] Experiment: Report DESKTOP resolution in +Subject: [PATCH 07/61] [settings] Experiment: Report DESKTOP resolution in video settings --- @@ -496,10 +496,10 @@ index c1cca7efdd5d119b07308b947c569911f2a9bdc9..e03f3c8ef21ba824c0d707042e5a735a StringUtils::Format("%dx%d%s", resolution->width, resolution->height, ModeFlagsToString(resolution->flags, false).c_str()), -From 03a66653809c1494b57bc1644af53c1c111a4765 Mon Sep 17 00:00:00 2001 +From 645bd37c7f9472f391282c5bee72b4d3378dd979 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 24 Sep 2014 23:13:52 +0100 -Subject: [PATCH 08/67] [audio] Add settings option to boost centre channel +Subject: [PATCH 08/61] [audio] Add settings option to boost centre channel when downmixing This allows a dB volume increase to be added to centre channel. @@ -517,10 +517,10 @@ Should work with Pi Sink (dvdplayer/paplayer) and omxplayer 5 files changed, 46 insertions(+) diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po -index 8860129ce3d4fd3426f6ba65d0c8cb8df18be8b2..f646446b73b2e8a3a783b2e52b3257c6ad6da2bd 100644 +index 62bd967a284b0b93820ef75bf8d76c3e78ee889d..dd36abb9f58c1ea2c6e5591c1b43f138434aad1c 100644 --- a/addons/resource.language.en_gb/resources/strings.po +++ b/addons/resource.language.en_gb/resources/strings.po -@@ -19305,6 +19305,21 @@ msgstr "" +@@ -19347,6 +19347,21 @@ msgstr "" #empty strings from id 38043 to 38099 @@ -543,10 +543,10 @@ index 8860129ce3d4fd3426f6ba65d0c8cb8df18be8b2..f646446b73b2e8a3a783b2e52b3257c6 #: system/settings/settings.xml msgctxt "#38100" diff --git a/system/settings/settings.xml b/system/settings/settings.xml -index c9d3c9dbe5bc5d41c8eb54babf78f9fe4046dd5c..2fad528a2f7ad57db8476c1879f853b8485d08e4 100644 +index 3ab531e9d4fa6c1305a833ba58aaf2a6c44ce310..f7a0ded4e39f1836c7a7cf19a3160d12a30e1a75 100644 --- a/system/settings/settings.xml +++ b/system/settings/settings.xml -@@ -2261,6 +2261,18 @@ +@@ -2268,6 +2268,18 @@ @@ -566,7 +566,7 @@ index c9d3c9dbe5bc5d41c8eb54babf78f9fe4046dd5c..2fad528a2f7ad57db8476c1879f853b8 HAS_AE_QUALITY_LEVELS 2 diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp -index 0cef1c58fae68f5a74d9ca31073282eb13abb037..23cd1eb96c2515eb5022f5b0220e67785b8aa4de 100644 +index b0ab84baf510d99ef66af86b88f2b23ea41f4e78..809ca88e64092c4c53045849fe98fd480a69651f 100644 --- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp @@ -20,6 +20,7 @@ @@ -577,7 +577,7 @@ index 0cef1c58fae68f5a74d9ca31073282eb13abb037..23cd1eb96c2515eb5022f5b0220e6778 #include "utils/log.h" extern "C" { -@@ -104,6 +105,12 @@ bool CActiveAEResampleFFMPEG::Init(uint64_t dst_chan_layout, int dst_channels, i +@@ -105,6 +106,12 @@ bool CActiveAEResampleFFMPEG::Init(uint64_t dst_chan_layout, int dst_channels, i { av_opt_set_double(m_pContext, "rematrix_maxval", 1.0, 0); } @@ -625,10 +625,10 @@ index f16b822ed7b4aebe18b5d339b3f71ee66e97c23f..993d4b33a294e88c2c004b7943895ba5 // stereo upmix if (upmix && m_src_channels == 2 && m_dst_channels > 2) -From db58404d482592303a170a3519ed43e552f3034a Mon Sep 17 00:00:00 2001 +From c092967c5512c2632533991f6cc25778ad2cb0af Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 27 Oct 2014 15:23:51 +0000 -Subject: [PATCH 09/67] [rbp] Default extract thumbnails to false +Subject: [PATCH 09/61] [rbp] Default extract thumbnails to false It can take 80 seconds for a single file on a Pi. It can cause crashes with out-of-memory errors. It genereates a lot of support issues. Best to default to disabled and let users enable it if they must @@ -637,7 +637,7 @@ It genereates a lot of support issues. Best to default to disabled and let users 1 file changed, 6 insertions(+) diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml -index 7e6e52f82fde4c91fdc004c4b4b46e86091bcc87..737ec4e0c7f0feb98a6dd008b53e238c41dde8af 100644 +index cf15fcbdb860608b2658b310614e1cd78cc94a18..770c628a15304856504676af82d46d57c97b86b8 100644 --- a/system/settings/rbp.xml +++ b/system/settings/rbp.xml @@ -43,6 +43,12 @@ @@ -654,10 +654,10 @@ index 7e6e52f82fde4c91fdc004c4b4b46e86091bcc87..737ec4e0c7f0feb98a6dd008b53e238c -From e2a04cad01c0fe85bec84480d05a58fe55f84bb2 Mon Sep 17 00:00:00 2001 +From 880e3ee7b784c9deddb66df4d80927699059c199 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Thu, 27 Nov 2014 16:31:56 +0000 -Subject: [PATCH 10/67] [languageinvoker] Reduce priority of python threads +Subject: [PATCH 10/61] [languageinvoker] Reduce priority of python threads --- xbmc/interfaces/generic/LanguageInvokerThread.cpp | 5 +++++ @@ -680,10 +680,10 @@ index fcdd0633f30cd9595ae6cc4ed293677cdcb1f422..16f0c8916b5e0a9e90973d194cf2ebd1 } -From e34bc9595b6b789d3b13165d7abcec3b25c83bfd Mon Sep 17 00:00:00 2001 +From de8e9ca53ad455e535526f9973fb775fbc349d6e Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sat, 14 Dec 2013 16:55:05 +0000 -Subject: [PATCH 11/67] logging: Add microsecond timer to log messages +Subject: [PATCH 11/61] logging: Add microsecond timer to log messages --- xbmc/utils/log.cpp | 15 +++++++++++++-- @@ -734,10 +734,10 @@ index 3443f1293d86018830269ed992c90a4e69c0430c..d330320842243df6f5ff256e608dddfa levelNames[logLevel]) + strData; -From 6a9154ceb989a8ca0f2c5f50c6746ade14125267 Mon Sep 17 00:00:00 2001 +From 9ca4200de7da40564dd08b6e1d955df3045f27d3 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sat, 29 Nov 2014 15:25:16 +0000 -Subject: [PATCH 12/67] [rbp] hack: wait for splash to complete before changing +Subject: [PATCH 12/61] [rbp] hack: wait for splash to complete before changing hdmi mode --- @@ -821,22 +821,22 @@ index ee297700f8583dbb15cbe53baf8c887b36bd2ea0..bbe501d40c5e101f1d0d64b8b59b1928 RENDER_STEREO_MODE stereo_mode = g_graphicsContext.GetStereoMode(); -From 6aa85041e715484b032f9e905db8c65388acfe17 Mon Sep 17 00:00:00 2001 +From c86a562cac08f054425e46f2c814b4f2f0d25a3a Mon Sep 17 00:00:00 2001 From: popcornmix Date: Thu, 11 Dec 2014 17:00:57 +0000 -Subject: [PATCH 13/67] Fix for UI not showing both extractflags and +Subject: [PATCH 13/61] Fix for UI not showing both extractflags and extractthumb --- - addons/resource.language.en_gb/resources/strings.po | 10 +++++++--- - system/settings/settings.xml | 4 ++-- - 2 files changed, 9 insertions(+), 5 deletions(-) + addons/resource.language.en_gb/resources/strings.po | 9 ++++++--- + system/settings/settings.xml | 4 ++-- + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po -index f646446b73b2e8a3a783b2e52b3257c6ad6da2bd..f1100b4238139b15799ddf1dba86265a1eaa53f3 100644 +index dd36abb9f58c1ea2c6e5591c1b43f138434aad1c..3208dad8988fba4bce7687861037274a42ffd21f 100644 --- a/addons/resource.language.en_gb/resources/strings.po +++ b/addons/resource.language.en_gb/resources/strings.po -@@ -12348,7 +12348,7 @@ msgstr "" +@@ -12385,7 +12385,7 @@ msgstr "" #: system/settings/settings.xml msgctxt "#20433" @@ -845,7 +845,7 @@ index f646446b73b2e8a3a783b2e52b3257c6ad6da2bd..f1100b4238139b15799ddf1dba86265a msgstr "" #: xbmc/dialogs/GUIDialogSmartPlaylistRule.cpp -@@ -16783,7 +16783,7 @@ msgstr "" +@@ -16821,7 +16821,7 @@ msgstr "" #. Description of setting with label #20433 "Extract thumbnails and video information" #: system/settings/settings.xml msgctxt "#36178" @@ -854,7 +854,7 @@ index f646446b73b2e8a3a783b2e52b3257c6ad6da2bd..f1100b4238139b15799ddf1dba86265a msgstr "" #. Description of setting with label #20419 "Replace file names with library titles" -@@ -16795,7 +16795,7 @@ msgstr "" +@@ -16833,7 +16833,7 @@ msgstr "" #. Description of setting with label #20433 "Extract thumbnails and video information" #: system/settings/settings.xml msgctxt "#36180" @@ -863,19 +863,18 @@ index f646446b73b2e8a3a783b2e52b3257c6ad6da2bd..f1100b4238139b15799ddf1dba86265a msgstr "" #: system/settings/settings.xml -@@ -19413,3 +19413,7 @@ msgstr "" - msgctxt "#39003" - msgid "Accelerate h264" +@@ -19480,3 +19480,6 @@ msgctxt "#39007" + msgid "This provides access to where picture sources can be added and otherwise managed." msgstr "" -+ + +msgctxt "#38190" +msgid "Extract thumbnails from video files" +msgstr "" diff --git a/system/settings/settings.xml b/system/settings/settings.xml -index 2fad528a2f7ad57db8476c1879f853b8485d08e4..ca7e8892606782e54d4883c5b2f0e6686b1ae280 100644 +index f7a0ded4e39f1836c7a7cf19a3160d12a30e1a75..88b67c1869246037e81fb3efbe293f9fee37d25e 100644 --- a/system/settings/settings.xml +++ b/system/settings/settings.xml -@@ -919,8 +919,8 @@ +@@ -972,8 +972,8 @@ true @@ -887,10 +886,10 @@ index 2fad528a2f7ad57db8476c1879f853b8485d08e4..ca7e8892606782e54d4883c5b2f0e668 -From 2900f0dc9fa9b7271efc13dfd219ee62a8737f6c Mon Sep 17 00:00:00 2001 +From 589e105736d4d65fea6812e1346317ed7afe518d Mon Sep 17 00:00:00 2001 From: anaconda Date: Thu, 11 Sep 2014 21:30:43 +0200 -Subject: [PATCH 14/67] Disable autoscrolling while on screensaver and while +Subject: [PATCH 14/61] Disable autoscrolling while on screensaver and while opening streams. --- @@ -903,10 +902,10 @@ Subject: [PATCH 14/67] Disable autoscrolling while on screensaver and while 6 files changed, 24 insertions(+), 3 deletions(-) diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp -index 39c5731cc13c028212c4776511ea978fa2cb6776..bf2f2d3e73cbc88ab9d89f91baa11f983f36ee10 100644 +index def6ed703b25087c4f61f71acb3fbb5257b8c44b..4fffdfad5296775161989468cb8197f892c204e1 100644 --- a/xbmc/Application.cpp +++ b/xbmc/Application.cpp -@@ -5198,3 +5198,13 @@ bool CApplication::NotifyActionListeners(const CAction &action) const +@@ -5188,3 +5188,13 @@ bool CApplication::NotifyActionListeners(const CAction &action) const return false; } @@ -921,10 +920,10 @@ index 39c5731cc13c028212c4776511ea978fa2cb6776..bf2f2d3e73cbc88ab9d89f91baa11f98 + return onBlackDimScreenSaver || openingStreams; +} diff --git a/xbmc/Application.h b/xbmc/Application.h -index 5d38663767a70875d9459a2f4a65979a203edc7b..1aca9fe67fea8436a15a5e2c07b6558b2bdf3ab7 100644 +index c14f62d54fd4623be82eff2d00097fc2c5615d3c..7126e1b1c73d75ff08a6bc58c5f98d5cba6a6fb1 100644 --- a/xbmc/Application.h +++ b/xbmc/Application.h -@@ -394,6 +394,8 @@ public: +@@ -393,6 +393,8 @@ public: */ void UnregisterActionListener(IActionListener *listener); @@ -1021,10 +1020,10 @@ index d7bc1c5ba6067af9a460589920367288c640a915..ac766293f1c47c7f145cb46f6b152144 if (m_lastRenderTime) m_autoScrollDelayTime += currentTime - m_lastRenderTime; -From 91f06fc770b8d9dee8086ab20a7111dc75664229 Mon Sep 17 00:00:00 2001 +From 6dfdde4dd31580ab361d73b46342ca78c2f1abce Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sat, 13 Dec 2014 18:35:20 +0000 -Subject: [PATCH 15/67] [demuxer] Avoid memcpy on every demuxer packet +Subject: [PATCH 15/61] [demuxer] Avoid memcpy on every demuxer packet Avoids an unnecessary memcpy on every demuxer packet which for high bitrate videos can be significant. @@ -1035,7 +1034,7 @@ high bitrate videos can be significant. 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -index 0b3643c70a9f0d18ccdbb04619d90f82e3b2f232..b9131402dff3a6d538a188794096bad5784dbb63 100644 +index 929f9879e28d6a496ddf713081dcece2cc773a48..bfdec6ffdb882465bb7a4b9db9bd6561963726de 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp @@ -851,7 +851,7 @@ DemuxPacket* CDVDDemuxFFmpeg::Read() @@ -1124,10 +1123,10 @@ index df0f35bd49c65b302de4ccd110d859e8b881ea5f..b4b591ae4c4dd4fb0b36d4d00fedca96 } catch(...) { -From a1f9425d9d9417c7f83806f41b724554653a1be6 Mon Sep 17 00:00:00 2001 +From 83e6d7254eb884e2aaf47445f58b1e96223c93d2 Mon Sep 17 00:00:00 2001 From: anaconda Date: Wed, 25 Feb 2015 18:22:21 +0100 -Subject: [PATCH 16/67] Load OSD dialogs on startup. +Subject: [PATCH 16/61] Load OSD dialogs on startup. Fixes skipped frames the first time they're loaded in memory on less powered devices, like a Raspberry Pi, when using DVDPlayer. @@ -1142,12 +1141,12 @@ See http://forum.kodi.tv/showthread.php?tid=211501&pid=1938811#pid1938811 6 files changed, 10 insertions(+), 4 deletions(-) diff --git a/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp b/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp -index 1f72db5b0726434505ee7f52296b909b98a5d133..bb2dd07f8c18e6e72c31feb6273b84b599265e0e 100644 +index 65071639e216a37d7b3cec119f1fe573718f44b6..52966fce668bbd1c58aa7e76feb5a2dbf93b1ab7 100644 --- a/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp +++ b/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp -@@ -50,6 +50,7 @@ CGUIDialogPVRChannelsOSD::CGUIDialogPVRChannelsOSD() : - CGUIDialog(WINDOW_DIALOG_PVR_OSD_CHANNELS, "DialogPVRChannelsOSD.xml"), - Observer() +@@ -49,6 +49,7 @@ using namespace KODI::MESSAGING; + CGUIDialogPVRChannelsOSD::CGUIDialogPVRChannelsOSD() : + CGUIDialog(WINDOW_DIALOG_PVR_OSD_CHANNELS, "DialogPVRChannelsOSD.xml") { + m_loadType = LOAD_ON_GUI_INIT; m_vecItems = new CFileItemList; @@ -1207,10 +1206,10 @@ index e498e1fd476d9ab5300bb00bc39946a22cfd93cb..a6648d016b07e2eb3e52f8d927697cc5 CGUIDialogVideoOSD::~CGUIDialogVideoOSD(void) diff --git a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp -index afbe2032b9b2235cd524263d8a730eb3402eb07f..89f685e5dc791a64dd74fa25356d62bbb74f5b58 100644 +index f9bc12da1aea3ea0926fefff93856cdd4328cb2f..ee6984c469023878b1fad18a29056b114d04fdcc 100644 --- a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp +++ b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp -@@ -66,7 +66,9 @@ +@@ -65,7 +65,9 @@ CGUIDialogVideoSettings::CGUIDialogVideoSettings() : CGUIDialogSettingsManualBase(WINDOW_DIALOG_VIDEO_OSD_SETTINGS, "DialogSettings.xml"), m_viewModeChanged(false) @@ -1222,10 +1221,10 @@ index afbe2032b9b2235cd524263d8a730eb3402eb07f..89f685e5dc791a64dd74fa25356d62bb CGUIDialogVideoSettings::~CGUIDialogVideoSettings() { } -From be39b1d7f8f1c217bb78888b18f2a27acc793031 Mon Sep 17 00:00:00 2001 +From b4180c7279375d6ef4c38535c6fa0b09b9cea66d Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 14 Apr 2015 20:51:14 +0100 -Subject: [PATCH 17/67] [gui] Also limit GUI updates when in non full-screen +Subject: [PATCH 17/61] [gui] Also limit GUI updates when in non full-screen video mode --- @@ -1233,10 +1232,10 @@ Subject: [PATCH 17/67] [gui] Also limit GUI updates when in non full-screen 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp -index bf2f2d3e73cbc88ab9d89f91baa11f983f36ee10..3ecce5b0ac4c1b9d3c4fc0dd759b31f1600ac7fa 100644 +index 4fffdfad5296775161989468cb8197f892c204e1..a98acfce3442f896250fad8003fb5991d1bf0bdc 100644 --- a/xbmc/Application.cpp +++ b/xbmc/Application.cpp -@@ -2707,7 +2707,7 @@ void CApplication::FrameMove(bool processEvents, bool processGUI) +@@ -2743,7 +2743,7 @@ void CApplication::FrameMove(bool processEvents, bool processGUI) #if defined(TARGET_RASPBERRY_PI) || defined(HAS_IMXVPU) // This code reduces rendering fps of the GUI layer when playing videos in fullscreen mode // it makes only sense on architectures with multiple layers @@ -1245,7 +1244,7 @@ index bf2f2d3e73cbc88ab9d89f91baa11f983f36ee10..3ecce5b0ac4c1b9d3c4fc0dd759b31f1 fps = CSettings::GetInstance().GetInt(CSettings::SETTING_VIDEOPLAYER_LIMITGUIUPDATE); #endif -@@ -2720,6 +2720,8 @@ void CApplication::FrameMove(bool processEvents, bool processGUI) +@@ -2756,6 +2756,8 @@ void CApplication::FrameMove(bool processEvents, bool processGUI) { if (!m_skipGuiRender) g_windowManager.Process(CTimeUtils::GetFrameTime()); @@ -1255,85 +1254,10 @@ index bf2f2d3e73cbc88ab9d89f91baa11f983f36ee10..3ecce5b0ac4c1b9d3c4fc0dd759b31f1 g_windowManager.FrameMove(); } -From 3dea2824fdcfe2448b5b6fd348569c34c5c12f84 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Tue, 21 Apr 2015 14:32:07 +0100 -Subject: [PATCH 18/67] [mmalrenderer] Add sharpness control - ---- - addons/resource.language.en_gb/resources/strings.po | 2 +- - .../VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp | 13 ++++++++++++- - .../VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.h | 1 + - 3 files changed, 14 insertions(+), 2 deletions(-) - -diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po -index f1100b4238139b15799ddf1dba86265a1eaa53f3..085e2a195d2e52ce6bea3ed791bf817f5be23b15 100644 ---- a/addons/resource.language.en_gb/resources/strings.po -+++ b/addons/resource.language.en_gb/resources/strings.po -@@ -8631,7 +8631,7 @@ msgstr "" - - #: xbmc/video/dialogs/GUIDialogVideoSettings.cpp - msgctxt "#16313" --msgid "VDPAU - Sharpness" -+msgid "Sharpness" - msgstr "" - - #: xbmc/video/dialogs/GUIDialogVideoSettings.cpp -diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp -index cd573128fdc7e24b5ecf19730b40ef35d1c67a14..d65857779628debfc85b47b8dd283513edb5a319 100644 ---- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp -+++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp -@@ -237,6 +237,7 @@ CMMALRenderer::CMMALRenderer() : CThread("MMALRenderer") - m_inflight = 0; - m_queue = nullptr; - m_error = 0.0; -+ m_sharpness = -2.0f; - } - - CMMALRenderer::~CMMALRenderer() -@@ -419,6 +420,15 @@ void CMMALRenderer::RenderUpdate(bool clear, DWORD flags, DWORD alpha) - - ManageRenderArea(); - -+ // if sharpness setting has changed, we should update it -+ if (m_sharpness != CMediaSettings::GetInstance().GetCurrentVideoSettings().m_Sharpness) -+ { -+ m_sharpness = CMediaSettings::GetInstance().GetCurrentVideoSettings().m_Sharpness; -+ char command[80], response[80]; -+ sprintf(command, "scaling_sharpness %d", ((int)(50.0f * (m_sharpness + 1.0f) + 0.5f))); -+ vc_gencmd(response, sizeof response, command); -+ } -+ - if (m_format != RENDER_FMT_MMAL) - { - if (g_advancedSettings.CanLogComponent(LOGVIDEO)) -@@ -608,7 +618,8 @@ bool CMMALRenderer::Supports(ERENDERFEATURE feature) - feature == RENDERFEATURE_ZOOM || - feature == RENDERFEATURE_ROTATION || - feature == RENDERFEATURE_VERTICAL_SHIFT || -- feature == RENDERFEATURE_PIXEL_RATIO) -+ feature == RENDERFEATURE_PIXEL_RATIO || -+ feature == RENDERFEATURE_SHARPNESS) - return true; - - return false; -diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.h b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.h -index e2c0223836af4171715a3907a5f7ac2511930f5f..ae0ce625c619910530f0b62ea8921aca0a3a7f63 100644 ---- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.h -+++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.h -@@ -116,6 +116,7 @@ protected: - bool m_StereoInvert; - int m_inflight; - bool m_opaque; -+ float m_sharpness; - AVPixelFormat m_pixfmt; - - CCriticalSection m_sharedSection; - -From 121a372d0e98284ede602670609158fc26f8a5be Mon Sep 17 00:00:00 2001 +From 7a8d7fb1bc28289af5f658441709c03bec33d092 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 5 May 2015 23:58:06 +0100 -Subject: [PATCH 19/67] [screensaver] Leave GUI contents available for +Subject: [PATCH 18/61] [screensaver] Leave GUI contents available for screensaver --- @@ -1341,10 +1265,10 @@ Subject: [PATCH 19/67] [screensaver] Leave GUI contents available for 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/xbmc/guilib/GUIWindowManager.cpp b/xbmc/guilib/GUIWindowManager.cpp -index 5835280d07f049329b05494cd30744c9c1f7a258..93f646e2b28efca6a4bdebbf458127ab597024eb 100644 +index 82b8b32eee8ab95555bbee462b36bfbf819f39b8..14b51568a959afa5648b844a2a87efbb57b5249a 100644 --- a/xbmc/guilib/GUIWindowManager.cpp +++ b/xbmc/guilib/GUIWindowManager.cpp -@@ -789,7 +789,16 @@ void CGUIWindowManager::ActivateWindow_Internal(int iWindowID, const std::vector +@@ -792,7 +792,16 @@ void CGUIWindowManager::ActivateWindow_Internal(int iWindowID, const std::vector int currentWindow = GetActiveWindow(); CGUIWindow *pWindow = GetWindow(currentWindow); if (pWindow) @@ -1363,10 +1287,10 @@ index 5835280d07f049329b05494cd30744c9c1f7a258..93f646e2b28efca6a4bdebbf458127ab // Add window to the history list (we must do this before we activate it, -From d0dac94c4e36e2c8d60311137194573b49ca3c9a Mon Sep 17 00:00:00 2001 +From 3baa1a6cc514b6ceeed4c10fe72d725395b28a06 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sat, 6 Jun 2015 18:43:57 +0100 -Subject: [PATCH 20/67] ffmpeg: Automatic switch to software decode for GMC +Subject: [PATCH 19/61] ffmpeg: Automatic switch to software decode for GMC with more than one warp point --- @@ -1458,20 +1382,20 @@ index c3998be2f3a5f1dbde2498be624fa8b48de7339f..dffe2da1dfd09e06c5f15c362f7cbe3c CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" CPPFLAGS="$(CPPFLAGS)" LDFLAGS="$(LDFLAGS)" \ ./configure $(ffmpg_config) diff --git a/tools/depends/target/ffmpeg/autobuild.sh b/tools/depends/target/ffmpeg/autobuild.sh -index 6bbebfca1c7189fec6650932d7292f17af60db62..9c26b239c2b2c1221bed7c4d99c46e909a4a5c5d 100755 +index 6bbebfca1c7189fec6650932d7292f17af60db62..e491c788793fa5df35e4570b54d7606183350376 100755 --- a/tools/depends/target/ffmpeg/autobuild.sh +++ b/tools/depends/target/ffmpeg/autobuild.sh @@ -127,6 +127,8 @@ mkdir -p "ffmpeg-${VERSION}" cd "ffmpeg-${VERSION}" || exit 2 tar --strip-components=1 -xf $MYDIR/${ARCHIVE} -+patch -p1 < ../../0001-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patch ++patch -p1 < ../0001-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patch + CFLAGS="$CFLAGS" CXXFLAGS="$CXXFLAGS" LDFLAGS="$LDFLAGS" \ ./configure --prefix=$FFMPEG_PREFIX \ --extra-version="kodi-${VERSION}" \ diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -index 51ded6b236418b7ff31b15b59e5da1b196f31fc2..c0e553ca060749edff28bcbb880ed3e149b9f751 100644 +index db15051b1638411e65c86de50a5be8f2ecbbd91c..c6f98ded45062617d88571cd70fc6336cfdc32c9 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp @@ -47,6 +47,10 @@ @@ -1485,7 +1409,7 @@ index 51ded6b236418b7ff31b15b59e5da1b196f31fc2..c0e553ca060749edff28bcbb880ed3e1 using namespace KODI::MESSAGING; #define CLASSNAME "CMMALVideoBuffer" -@@ -540,6 +544,8 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) +@@ -367,6 +371,8 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) // we always qualify even if DVDFactoryCodec does this too. if (!CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_USEMMAL) || hints.software) return false; @@ -1495,7 +1419,7 @@ index 51ded6b236418b7ff31b15b59e5da1b196f31fc2..c0e553ca060749edff28bcbb880ed3e1 m_processInfo.SetVideoDeintMethod("none"); diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemux.h b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemux.h -index 23cd50ce4643d32fc8f97bc612e9e911169f32d1..86ac5175b0ff1481571beaf0617471e122ee05a1 100644 +index 03fdf6efa072219d55cac21b7f7923ffc6c00e17..e3a32aebfe59016b43cd7c2b304921b58c44e129 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemux.h +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemux.h @@ -157,6 +157,7 @@ public: @@ -1515,10 +1439,10 @@ index 23cd50ce4643d32fc8f97bc612e9e911169f32d1..86ac5175b0ff1481571beaf0617471e1 class CDemuxStreamAudio : public CDemuxStream diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -index b9131402dff3a6d538a188794096bad5784dbb63..84310bbda6440dd10f9aa0711859f4dc0bb1fd1a 100644 +index bfdec6ffdb882465bb7a4b9db9bd6561963726de..c8ba4f869e844550e47ab9084aad1c59ba10f53a 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -@@ -1310,7 +1310,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) +@@ -1323,7 +1323,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) if (!stereoMode.empty()) st->stereo_mode = stereoMode; @@ -1568,7 +1492,7 @@ index f14170850673ebf746df0acf8f5cf5977feae684..85e402bb4e1ddd61bdb657802cc7347c // AUDIO int channels; diff --git a/xbmc/cores/omxplayer/OMXHelper.cpp b/xbmc/cores/omxplayer/OMXHelper.cpp -index b5db1c4ec03e4b5809a14c541329ee11aa7df04f..344f393cfa2230b21a8dba42ef3cf79ce428dac2 100644 +index f135d423c0ca76fd70e79ae5b7d035f0cb79fc75..d9b576bc46055fdab1c134e5f2c63cd4989d015c 100644 --- a/xbmc/cores/omxplayer/OMXHelper.cpp +++ b/xbmc/cores/omxplayer/OMXHelper.cpp @@ -30,6 +30,10 @@ @@ -1594,10 +1518,10 @@ index b5db1c4ec03e4b5809a14c541329ee11aa7df04f..344f393cfa2230b21a8dba42ef3cf79c else if ((hint.codec == AV_CODEC_ID_VC1 || hint.codec == AV_CODEC_ID_WMV3) && g_RBP.GetCodecWvc1()) supported = true; -From e7ca15df03877b289fcaed9838e49758982ecacf Mon Sep 17 00:00:00 2001 +From 43dc7e2beea8ce8abebc3ae26ac7ac31263949ee Mon Sep 17 00:00:00 2001 From: popcornmix Date: Thu, 10 Mar 2016 17:56:11 +0000 -Subject: [PATCH 21/67] [rbp] HW mouse pointer +Subject: [PATCH 20/61] [rbp] HW mouse pointer Updating the mouse point provokes a complete screen update which can make it feel laggy and results in high cpu. @@ -1612,10 +1536,10 @@ Render the mouse with an overlay to avoid redrawing the normal gui. 5 files changed, 282 insertions(+) diff --git a/xbmc/guilib/GUIWindowManager.cpp b/xbmc/guilib/GUIWindowManager.cpp -index 93f646e2b28efca6a4bdebbf458127ab597024eb..4bedbdde8c9b226e86a0c37378597bd524dbe66e 100644 +index 14b51568a959afa5648b844a2a87efbb57b5249a..5384f5686578ee455263b0ee636b2adc332e0264 100644 --- a/xbmc/guilib/GUIWindowManager.cpp +++ b/xbmc/guilib/GUIWindowManager.cpp -@@ -198,7 +198,9 @@ void CGUIWindowManager::CreateWindows() +@@ -199,7 +199,9 @@ void CGUIWindowManager::CreateWindows() Add(new CGUIWindowAddonBrowser); Add(new CGUIWindowScreensaverDim); Add(new CGUIWindowDebugInfo); @@ -1626,7 +1550,7 @@ index 93f646e2b28efca6a4bdebbf458127ab597024eb..4bedbdde8c9b226e86a0c37378597bd5 Add(new CGUIDialogProgress); Add(new CGUIDialogExtendedProgressBar); diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp -index ddbe27061f8192b7f6c830a4c22652a731537079..fbffa3a952d920cb41412f00f59d5c1c91f98740 100644 +index 6b06c253644a85ca6a5088b07ca41369e38f21d0..92f20e5174dd6b886cf622460ac68ab5f2fe24b9 100644 --- a/xbmc/linux/RBP.cpp +++ b/xbmc/linux/RBP.cpp @@ -28,6 +28,9 @@ @@ -2030,4400 +1954,10 @@ index 1b1d2f2e60334ed0f3a9964d106957f58e69f1b3..c82ba84625fe3556ff49764d40ceb3ec #endif -From f5e09c6ab9f5544d67f94305998b8a3b13f27b9a Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Tue, 10 Feb 2015 16:39:12 +0000 -Subject: [PATCH 22/67] [librtmp] Update to 15-Dec-2015 from - http://stream-recorder.com/forum/customized-rtmpdump-binaries-patch-file-t16103.html - ---- - tools/depends/target/librtmp/Makefile | 5 +- - tools/depends/target/librtmp/Patch.diff | 4066 ++++++++++++++++++++++ - tools/depends/target/librtmp/UpdateToLatest.diff | 257 ++ - tools/depends/target/librtmp/libm.patch | 11 - - 4 files changed, 4326 insertions(+), 13 deletions(-) - create mode 100644 tools/depends/target/librtmp/Patch.diff - create mode 100644 tools/depends/target/librtmp/UpdateToLatest.diff - delete mode 100644 tools/depends/target/librtmp/libm.patch - -diff --git a/tools/depends/target/librtmp/Makefile b/tools/depends/target/librtmp/Makefile -index e78d375b1284957036a549a65b8493582cea82e6..03fee99576ab943c72bfb1f5c5b1ccc88450a63a 100644 ---- a/tools/depends/target/librtmp/Makefile -+++ b/tools/depends/target/librtmp/Makefile -@@ -1,5 +1,5 @@ - include ../../Makefile.include --DEPS= ../../Makefile.include Makefile prefix.patch -+DEPS= ../../Makefile.include Makefile prefix.patch UpdateToLatest.diff Patch.diff - - # lib name, version - LIBNAME=rtmpdump -@@ -27,7 +27,8 @@ $(PLATFORM): $(TARBALLS_LOCATION)/$(ARCHIVE) $(DEPS) - rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) - cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) - cd $(PLATFORM); patch -p0 < ../prefix.patch -- cd $(PLATFORM)/librtmp; patch -p0 < ../../libm.patch -+ cd $(PLATFORM); patch -p1 < ../UpdateToLatest.diff -+ cd $(PLATFORM); patch -p0 < ../Patch.diff - sed -i -e 's|CC=|#CC=|' $(PLATFORM)/librtmp/Makefile - sed -i -e 's|LD=|#LD=|' $(PLATFORM)/librtmp/Makefile - sed -i -e 's|AR=|#AR=|' $(PLATFORM)/librtmp/Makefile -diff --git a/tools/depends/target/librtmp/Patch.diff b/tools/depends/target/librtmp/Patch.diff -new file mode 100644 -index 0000000000000000000000000000000000000000..62c1e990e73f61dd205028c3acae0e57d5953f76 ---- /dev/null -+++ b/tools/depends/target/librtmp/Patch.diff -@@ -0,0 +1,4066 @@ -+diff --git Makefile Makefile -+index a1595a8..9fe7584 100644 -+--- Makefile -++++ Makefile -+@@ -32,7 +32,7 @@ BINDIR=$(DESTDIR)$(bindir) -+ SBINDIR=$(DESTDIR)$(sbindir) -+ MANDIR=$(DESTDIR)$(mandir) -+ -+-LIBS_posix= -++LIBS_posix=-lm -+ LIBS_darwin= -+ LIBS_mingw=-lws2_32 -lwinmm -lgdi32 -+ LIB_RTMP=-Llibrtmp -lrtmp -+diff --git librtmp/Makefile librtmp/Makefile -+index 2c1c790..e367535 100644 -+--- librtmp/Makefile -++++ librtmp/Makefile -+@@ -26,7 +26,7 @@ REQ_GNUTLS=gnutls,hogweed,nettle -+ REQ_OPENSSL=libssl,libcrypto -+ PUB_GNUTLS=-lgmp -+ LIBZ=-lz -+-LIBS_posix= -++LIBS_posix=-lm -+ LIBS_darwin= -+ LIBS_mingw=-lws2_32 -lwinmm -lgdi32 -+ LIB_GNUTLS=-lgnutls -lhogweed -lnettle -lgmp $(LIBZ) -+diff --git librtmp/amf.c librtmp/amf.c -+index 1c5f99f..1310cbe 100644 -+--- librtmp/amf.c -++++ librtmp/amf.c -+@@ -319,6 +319,13 @@ AMFProp_SetName(AMFObjectProperty *prop, AVal *name) -+ prop->p_name = *name; -+ } -+ -++void -++AMFProp_SetString(AMFObjectProperty *prop, AVal *str) -++{ -++ prop->p_type = AMF_STRING; -++ prop->p_vu.p_aval = *str; -++} -++ -+ AMFDataType -+ AMFProp_GetType(AMFObjectProperty *prop) -+ { -+@@ -503,6 +510,9 @@ AMF3Prop_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize, -+ return -1; -+ } -+ -++ if (*pBuffer == AMF3_NULL) -++ bDecodeName = FALSE; -++ -+ /* decode name */ -+ if (bDecodeName) -+ { -+@@ -586,7 +596,7 @@ AMF3Prop_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize, -+ } -+ case AMF3_OBJECT: -+ { -+- int nRes = AMF3_Decode(&prop->p_vu.p_object, pBuffer, nSize, TRUE); -++ int nRes = AMF3_Decode(&prop->p_vu.p_object, pBuffer, nSize, FALSE); -+ if (nRes == -1) -+ return -1; -+ nSize -= nRes; -+@@ -620,6 +630,9 @@ AMFProp_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize, -+ return -1; -+ } -+ -++ if (*pBuffer == AMF_NULL) -++ bDecodeName = FALSE; -++ -+ if (bDecodeName && nSize < 4) -+ { /* at least name (length + at least 1 byte) and 1 byte of data */ -+ RTMP_Log(RTMP_LOGDEBUG, -+@@ -649,9 +662,8 @@ AMFProp_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize, -+ return -1; -+ } -+ -+- nSize--; -+- -+ prop->p_type = *pBuffer++; -++ nSize--; -+ switch (prop->p_type) -+ { -+ case AMF_NUMBER: -+@@ -697,9 +709,13 @@ AMFProp_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize, -+ break; -+ case AMF_REFERENCE: -+ { -+- RTMP_Log(RTMP_LOGERROR, "AMF_REFERENCE not supported!"); -+- return -1; -+- break; -++ RTMP_Log(RTMP_LOGDEBUG, "AMF_REFERENCE is not fully supported!"); -++ if (nSize < 2) -++ return -1; -++ prop->p_type = AMF_NUMBER; -++ prop->p_vu.p_number = AMF_DecodeInt16(pBuffer); -++ nSize -= 2; -++ break; -+ } -+ case AMF_ECMA_ARRAY: -+ { -+@@ -731,13 +747,13 @@ AMFProp_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize, -+ } -+ case AMF_DATE: -+ { -+- RTMP_Log(RTMP_LOGDEBUG, "AMF_DATE"); -+- -+ if (nSize < 10) -+ return -1; -+ -+ prop->p_vu.p_number = AMF_DecodeNumber(pBuffer); -+ prop->p_UTCoffset = AMF_DecodeInt16(pBuffer + 8); -++ RTMP_Log(RTMP_LOGDEBUG, "AMF_DATE: %f, UTC offset: %d", prop->p_vu.p_number, -++ prop->p_UTCoffset); -+ -+ nSize -= 10; -+ break; -+@@ -809,8 +825,8 @@ AMFProp_Dump(AMFObjectProperty *prop) -+ } -+ else -+ { -+- name.av_val = "no-name."; -+- name.av_len = sizeof("no-name.") - 1; -++ name.av_val = "no-name"; -++ name.av_len = sizeof ("no-name") - 1; -+ } -+ if (name.av_len > 18) -+ name.av_len = 18; -+@@ -1021,11 +1037,18 @@ AMF3_Decode(AMFObject *obj, const char *pBuffer, int nSize, int bAMFData) -+ obj->o_props = NULL; -+ if (bAMFData) -+ { -+- if (*pBuffer != AMF3_OBJECT) -+- RTMP_Log(RTMP_LOGERROR, -+- "AMF3 Object encapsulated in AMF stream does not start with AMF3_OBJECT!"); -+- pBuffer++; -+- nSize--; -++ // Decode only if it's an AMF3 object -++ if (*pBuffer == AMF3_OBJECT) -++ { -++ pBuffer++; -++ nSize--; -++ } -++ else -++ { -++ RTMP_Log(RTMP_LOGERROR, "AMF3 Object encapsulated in AMF stream does not start with AMF3_OBJECT!"); -++ pBuffer += nOriginalSize; -++ return nOriginalSize; -++ } -+ } -+ -+ ref = 0; -+@@ -1043,8 +1066,12 @@ AMF3_Decode(AMFObject *obj, const char *pBuffer, int nSize, int bAMFData) -+ { -+ int32_t classRef = (ref >> 1); -+ -+- AMF3ClassDef cd = { {0, 0} -+- }; -++ AMF3ClassDef cd; -++ cd.cd_name.av_len = 0; -++ cd.cd_name.av_val = 0; -++ cd.cd_externalizable = FALSE; -++ cd.cd_dynamic = TRUE; -++ cd.cd_num = 0; -+ AMFObjectProperty prop; -+ -+ if ((classRef & 0x1) == 0) -+@@ -1061,6 +1088,7 @@ AMF3_Decode(AMFObject *obj, const char *pBuffer, int nSize, int bAMFData) -+ cd.cd_dynamic = ((classExtRef >> 1) & 0x1) == 1; -+ -+ cdnum = classExtRef >> 2; -++ cd.cd_num = cdnum; -+ -+ /* class name */ -+ -+@@ -1070,24 +1098,25 @@ AMF3_Decode(AMFObject *obj, const char *pBuffer, int nSize, int bAMFData) -+ -+ /*std::string str = className; */ -+ -+- RTMP_Log(RTMP_LOGDEBUG, -+- "Class name: %s, externalizable: %d, dynamic: %d, classMembers: %d", -+- cd.cd_name.av_val, cd.cd_externalizable, cd.cd_dynamic, -+- cd.cd_num); -++ RTMP_Log(RTMP_LOGDEBUG, "Class name: %.*s, externalizable: %d, dynamic: %d, classMembers: %d", -++ cd.cd_name.av_len, cd.cd_name.av_val, cd.cd_externalizable, cd.cd_dynamic, cd.cd_num); -+ -+ for (i = 0; i < cdnum; i++) -+- { -+- AVal memberName; -+- if (nSize <=0) -++ { -++ AVal memberName = {NULL, 0}; -++ if (nSize <= 0) -+ { -+ invalid: -+ RTMP_Log(RTMP_LOGDEBUG, "%s, invalid class encoding!", -+ __FUNCTION__); -+ return nOriginalSize; -+- } -+- len = AMF3ReadString(pBuffer, &memberName); -+- RTMP_Log(RTMP_LOGDEBUG, "Member: %s", memberName.av_val); -+- AMF3CD_AddProp(&cd, &memberName); -++ } -++ len = AMF3ReadString(pBuffer, &memberName); -++ if (memberName.av_val) -++ { -++ RTMP_Log(RTMP_LOGDEBUG, "Member: %.*s", memberName.av_len, memberName.av_val); -++ AMF3CD_AddProp(&cd, &memberName); -++ } -+ nSize -= len; -+ pBuffer += len; -+ } -+@@ -1118,10 +1147,10 @@ invalid: -+ else -+ { -+ int nRes, i; -+- for (i = 0; i < cd.cd_num; i++) /* non-dynamic */ -+- { -+- if (nSize <=0) -+- goto invalid; -++ for (i = 0; i < cd.cd_num; i++) /* non-dynamic */ -++ { -++ if (nSize <= 0) -++ goto invalid; -+ nRes = AMF3Prop_Decode(&prop, pBuffer, nSize, FALSE); -+ if (nRes == -1) -+ RTMP_Log(RTMP_LOGDEBUG, "%s, failed to decode AMF3 property!", -+@@ -1138,9 +1167,9 @@ invalid: -+ int len = 0; -+ -+ do -+- { -+- if (nSize <=0) -+- goto invalid; -++ { -++ if (nSize <= 0) -++ goto invalid; -+ nRes = AMF3Prop_Decode(&prop, pBuffer, nSize, TRUE); -+ AMF_AddProp(obj, &prop); -+ -+@@ -1154,7 +1183,15 @@ invalid: -+ } -+ RTMP_Log(RTMP_LOGDEBUG, "class object!"); -+ } -+- return nOriginalSize - nSize; -++ -++ /** -++ * In case of switch to AMF3 serialization consume rest of the unprocessed -++ * packet data to make sure it's not later processed as AMF0 data. -++ */ -++ if (bAMFData) -++ return nOriginalSize; -++ else -++ return nOriginalSize - nSize; -+ } -+ -+ int -+@@ -1272,7 +1309,8 @@ AMF3CD_AddProp(AMF3ClassDef *cd, AVal *prop) -+ { -+ if (!(cd->cd_num & 0x0f)) -+ cd->cd_props = realloc(cd->cd_props, (cd->cd_num + 16) * sizeof(AVal)); -+- cd->cd_props[cd->cd_num++] = *prop; -++ if (cd->cd_props) -++ cd->cd_props[cd->cd_num++] = *prop; -+ } -+ -+ AVal * -+diff --git librtmp/handshake.h librtmp/handshake.h -+index 0438486..104af28 100644 -+--- librtmp/handshake.h -++++ librtmp/handshake.h -+@@ -707,7 +707,7 @@ HandShake(RTMP * r, int FP9HandShake) -+ uint32_t uptime; -+ -+ uint8_t clientbuf[RTMP_SIG_SIZE + 4], *clientsig=clientbuf+4; -+- uint8_t serversig[RTMP_SIG_SIZE], client2[RTMP_SIG_SIZE], *reply; -++ uint8_t serversig[RTMP_SIG_SIZE], serversig1[RTMP_SIG_SIZE], client2[RTMP_SIG_SIZE], *reply; -+ uint8_t type; -+ getoff *getdh = NULL, *getdig = NULL; -+ -+@@ -760,7 +760,7 @@ HandShake(RTMP * r, int FP9HandShake) -+ #else -+ ip = (int32_t *)(clientsig+8); -+ for (i = 2; i < RTMP_SIG_SIZE/4; i++) -+- *ip++ = rand(); -++ *ip++ = ((rand() & 0xFFFF) << 16) | (rand() & 0xFFFF); -+ #endif -+ -+ /* set handshake digest */ -+@@ -825,6 +825,8 @@ HandShake(RTMP * r, int FP9HandShake) -+ -+ if (ReadN(r, (char *)serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE) -+ return FALSE; -++ if (ReadN(r, (char *) serversig1, RTMP_SIG_SIZE) != RTMP_SIG_SIZE) -++ return FALSE; -+ -+ /* decode server response */ -+ memcpy(&uptime, serversig, 4); -+@@ -834,7 +836,7 @@ HandShake(RTMP * r, int FP9HandShake) -+ RTMP_Log(RTMP_LOGDEBUG, "%s: FMS Version : %d.%d.%d.%d", __FUNCTION__, serversig[4], -+ serversig[5], serversig[6], serversig[7]); -+ -+- if (FP9HandShake && type == 3 && !serversig[4]) -++ if (FP9HandShake && type == 3 && (!serversig[4] || !serversig1[4])) -+ FP9HandShake = FALSE; -+ -+ #ifdef _DEBUG -+@@ -914,7 +916,7 @@ HandShake(RTMP * r, int FP9HandShake) -+ #else -+ ip = (int32_t *)reply; -+ for (i = 0; i < RTMP_SIG_SIZE/4; i++) -+- *ip++ = rand(); -++ *ip++ = ((rand() & 0xFFFF) << 16) | (rand() & 0xFFFF); -+ #endif -+ /* calculate response now */ -+ signatureResp = reply+RTMP_SIG_SIZE-SHA256_DIGEST_LENGTH; -+@@ -965,16 +967,22 @@ HandShake(RTMP * r, int FP9HandShake) -+ __FUNCTION__); -+ RTMP_LogHex(RTMP_LOGDEBUG, reply, RTMP_SIG_SIZE); -+ #endif -+- if (!WriteN(r, (char *)reply, RTMP_SIG_SIZE)) -+- return FALSE; -+- -+- /* 2nd part of handshake */ -+- if (ReadN(r, (char *)serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE) -+- return FALSE; -++ if (r->Link.CombineConnectPacket) -++ { -++ char *HandshakeResponse = malloc(RTMP_SIG_SIZE); -++ memcpy(HandshakeResponse, (char *) reply, RTMP_SIG_SIZE); -++ r->Link.HandshakeResponse.av_val = HandshakeResponse; -++ r->Link.HandshakeResponse.av_len = RTMP_SIG_SIZE; -++ } -++ else -++ { -++ if (!WriteN(r, (char *) reply, RTMP_SIG_SIZE)) -++ return FALSE; -++ } -+ -+ #ifdef _DEBUG -+ RTMP_Log(RTMP_LOGDEBUG, "%s: 2nd handshake: ", __FUNCTION__); -+- RTMP_LogHex(RTMP_LOGDEBUG, serversig, RTMP_SIG_SIZE); -++ RTMP_LogHex(RTMP_LOGDEBUG, serversig1, RTMP_SIG_SIZE); -+ #endif -+ -+ if (FP9HandShake) -+@@ -982,21 +990,21 @@ HandShake(RTMP * r, int FP9HandShake) -+ uint8_t signature[SHA256_DIGEST_LENGTH]; -+ uint8_t digest[SHA256_DIGEST_LENGTH]; -+ -+- if (serversig[4] == 0 && serversig[5] == 0 && serversig[6] == 0 -+- && serversig[7] == 0) -++ if (serversig1[4] == 0 && serversig1[5] == 0 && serversig1[6] == 0 -++ && serversig1[7] == 0) -+ { -+ RTMP_Log(RTMP_LOGDEBUG, -+ "%s: Wait, did the server just refuse signed authentication?", -+ __FUNCTION__); -+ } -+ RTMP_Log(RTMP_LOGDEBUG, "%s: Server sent signature:", __FUNCTION__); -+- RTMP_LogHex(RTMP_LOGDEBUG, &serversig[RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH], -++ RTMP_LogHex(RTMP_LOGDEBUG, &serversig1[RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH], -+ SHA256_DIGEST_LENGTH); -+ -+ /* verify server response */ -+ HMACsha256(&clientsig[digestPosClient], SHA256_DIGEST_LENGTH, -+ GenuineFMSKey, sizeof(GenuineFMSKey), digest); -+- HMACsha256(serversig, RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH, digest, -++ HMACsha256(serversig1, RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH, digest, -+ SHA256_DIGEST_LENGTH, signature); -+ -+ /* show some information */ -+@@ -1024,7 +1032,7 @@ HandShake(RTMP * r, int FP9HandShake) -+ RTMP_Log(RTMP_LOGDEBUG, "%s: Signature calculated:", __FUNCTION__); -+ RTMP_LogHex(RTMP_LOGDEBUG, signature, SHA256_DIGEST_LENGTH); -+ if (memcmp -+- (signature, &serversig[RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH], -++ (signature, &serversig1[RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH], -+ SHA256_DIGEST_LENGTH) != 0) -+ { -+ RTMP_Log(RTMP_LOGWARNING, "%s: Server not genuine Adobe!", __FUNCTION__); -+@@ -1057,7 +1065,7 @@ HandShake(RTMP * r, int FP9HandShake) -+ } -+ else -+ { -+- if (memcmp(serversig, clientsig, RTMP_SIG_SIZE) != 0) -++ if (memcmp(serversig1, clientsig, RTMP_SIG_SIZE) != 0) -+ { -+ RTMP_Log(RTMP_LOGWARNING, "%s: client signature does not match!", -+ __FUNCTION__); -+@@ -1099,7 +1107,7 @@ SHandShake(RTMP * r) -+ { -+ encrypted = FALSE; -+ } -+- else if (type == 6 || type == 8) -++ else if (type == 6 || type == 8 || type == 9) -+ { -+ offalg = 1; -+ encrypted = TRUE; -+@@ -1148,7 +1156,7 @@ SHandShake(RTMP * r) -+ #else -+ ip = (int32_t *)(serversig+8); -+ for (i = 2; i < RTMP_SIG_SIZE/4; i++) -+- *ip++ = rand(); -++ *ip++ = ((rand() & 0xFFFF) << 16) | (rand() & 0xFFFF); -+ #endif -+ -+ /* set handshake digest */ -+diff --git librtmp/hashswf.c librtmp/hashswf.c -+index 9f4e2c0..01b97e2 100644 -+--- librtmp/hashswf.c -++++ librtmp/hashswf.c -+@@ -70,7 +70,7 @@ extern TLS_CTX RTMP_TLS_ctx; -+ -+ #endif /* CRYPTO */ -+ -+-#define AGENT "Mozilla/5.0" -++#define AGENT "Mozilla/5.0 (Windows NT 5.1; rv:21.0) Gecko/20100101 Firefox/21.0" -+ -+ HTTPResult -+ HTTP_get(struct HTTP_ctx *http, const char *url, HTTP_read_callback *cb) -+@@ -116,6 +116,8 @@ HTTP_get(struct HTTP_ctx *http, const char *url, HTTP_read_callback *cb) -+ -+ host = p1 + 3; -+ path = strchr(host, '/'); -++ if (!path) -++ return HTTPRES_BAD_REQUEST; -+ hlen = path - host; -+ strncpy(hbuf, host, hlen); -+ hbuf[hlen] = '\0'; -+@@ -200,7 +202,7 @@ HTTP_get(struct HTTP_ctx *http, const char *url, HTTP_read_callback *cb) -+ } -+ -+ p1 = strchr(sb.sb_buf, ' '); -+- rc = atoi(p1 + 1); -++ rc = p1 ? atoi(p1 + 1) : 400; -+ http->status = rc; -+ -+ if (rc >= 300) -+@@ -379,13 +381,13 @@ make_unix_time(char *s) -+ if (fmt) -+ { -+ /* Day, DD-MMM-YYYY HH:MM:SS GMT */ -+- time.tm_mday = strtol(n + 1, &n, 0); -++ time.tm_mday = strtol(n + 1, &n, 10); -+ month = n + 1; -+ n = strchr(month, ' '); -+- time.tm_year = strtol(n + 1, &n, 0); -+- time.tm_hour = strtol(n + 1, &n, 0); -+- time.tm_min = strtol(n + 1, &n, 0); -+- time.tm_sec = strtol(n + 1, NULL, 0); -++ time.tm_year = strtol(n + 1, &n, 10); -++ time.tm_hour = strtol(n + 1, &n, 10); -++ time.tm_min = strtol(n + 1, &n, 10); -++ time.tm_sec = strtol(n + 1, NULL, 10); -+ } -+ else -+ { -+@@ -395,11 +397,11 @@ make_unix_time(char *s) -+ n = strchr(month, ' '); -+ while (isspace(*n)) -+ n++; -+- time.tm_mday = strtol(n, &n, 0); -+- time.tm_hour = strtol(n + 1, &n, 0); -+- time.tm_min = strtol(n + 1, &n, 0); -+- time.tm_sec = strtol(n + 1, &n, 0); -+- time.tm_year = strtol(n + 1, NULL, 0); -++ time.tm_mday = strtol(n, &n, 10); -++ time.tm_hour = strtol(n + 1, &n, 10); -++ time.tm_min = strtol(n + 1, &n, 10); -++ time.tm_sec = strtol(n + 1, &n, 10); -++ time.tm_year = strtol(n + 1, NULL, 10); -+ } -+ if (time.tm_year > 100) -+ time.tm_year -= ysub; -+@@ -528,9 +530,11 @@ RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash, -+ -+ if (strncmp(buf, "url: ", 5)) -+ continue; -+- if (strncmp(buf + 5, url, hlen)) -++ if (strncmp(buf + 5, url, strlen(buf + 5) - 1)) -+ continue; -+ r1 = strrchr(buf, '/'); -++ if (!r1) -++ continue; -+ i = strlen(r1); -+ r1[--i] = '\0'; -+ if (strncmp(r1, file, i)) -+@@ -640,7 +644,7 @@ RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash, -+ HMAC_finish(in.ctx, hash, hlen); -+ *size = in.size; -+ -+- fprintf(f, "date: %s\n", date); -++ fprintf(f, "date: %s\n", date[0] ? date : cctim); -+ fprintf(f, "size: %08x\n", in.size); -+ fprintf(f, "hash: "); -+ for (i = 0; i < SHA256_DIGEST_LENGTH; i++) -+diff --git librtmp/log.c librtmp/log.c -+index 1b52000..7564a15 100644 -+--- librtmp/log.c -++++ librtmp/log.c -+@@ -52,8 +52,8 @@ static void rtmp_log_default(int level, const char *format, va_list vl) -+ vsnprintf(str, MAX_PRINT_LEN-1, format, vl); -+ -+ /* Filter out 'no-name' */ -+- if ( RTMP_debuglevelav_val = p; -+ app->av_len = applen; -+ RTMP_Log(RTMP_LOGDEBUG, "Parsed app : %.*s", applen, p); -+diff --git librtmp/rtmp.c librtmp/rtmp.c -+index ca7db6a..c652cff 100644 -+--- librtmp/rtmp.c -++++ librtmp/rtmp.c -+@@ -28,6 +28,7 @@ -+ #include -+ #include -+ #include -++#include -+ -+ #include "rtmp_sys.h" -+ #include "log.h" -+@@ -68,6 +69,7 @@ TLS_CTX RTMP_TLS_ctx; -+ -+ #define RTMP_SIG_SIZE 1536 -+ #define RTMP_LARGE_HEADER_SIZE 12 -++#define HEX2BIN(a) (((a)&0x40)?((a)&0xf)+9:((a)&0xf)) -+ -+ static const int packetSize[] = { 12, 8, 4, 1 }; -+ -+@@ -108,18 +110,25 @@ typedef enum { -+ RTMPT_OPEN=0, RTMPT_SEND, RTMPT_IDLE, RTMPT_CLOSE -+ } RTMPTCmd; -+ -++static int ConnectSocket(RTMP *r); -+ static int DumpMetaData(AMFObject *obj); -+ static int HandShake(RTMP *r, int FP9HandShake); -+ static int SocksNegotiate(RTMP *r); -+ -++static int SendBytesReceived(RTMP *r); -++static int SendCommand(RTMP *r, char *method, int queue); -+ static int SendConnectPacket(RTMP *r, RTMPPacket *cp); -+ static int SendCheckBW(RTMP *r); -+ static int SendCheckBWResult(RTMP *r, double txn); -+ static int SendDeleteStream(RTMP *r, double dStreamId); -+ static int SendFCSubscribe(RTMP *r, AVal *subscribepath); -++static int SendGetStreamLength(RTMP *r); -++static int SendInvoke(RTMP *r, AVal *command, int queue); -+ static int SendPlay(RTMP *r); -+-static int SendBytesReceived(RTMP *r); -+ static int SendUsherToken(RTMP *r, AVal *usherToken); -++static void TransformRot13(AMFObject *obj, AVal *rindex, AVal *r); -++static void __TeaCrypt(uint32_t *block, uint32_t len, uint32_t *key); -++static AVal TeaEncrypt(AVal *srcData, AVal *srcKey); -+ -+ #if 0 /* unused */ -+ static int SendBGHasStream(RTMP *r, double dId, AVal *playpath); -+@@ -338,10 +347,15 @@ RTMP_Init(RTMP *r) -+ r->m_nClientBW = 2500000; -+ r->m_nClientBW2 = 2; -+ r->m_nServerBW = 2500000; -+- r->m_fAudioCodecs = 3191.0; -++ r->m_fAudioCodecs = 3575.0; -+ r->m_fVideoCodecs = 252.0; -++ r->m_fEncoding = 3.0; -+ r->Link.timeout = 30; -+ r->Link.swfAge = 30; -++ r->Link.CombineConnectPacket = TRUE; -++ r->Link.ConnectPacket = FALSE; -++ r->Link.publishId = 0; -++ r->Link.dynamicPublish = FALSE; -+ } -+ -+ void -+@@ -359,6 +373,8 @@ RTMP_GetDuration(RTMP *r) -+ int -+ RTMP_IsConnected(RTMP *r) -+ { -++ if (r->m_sb.sb_size > 0) -++ return TRUE; -+ return r->m_sb.sb_socket != -1; -+ } -+ -+@@ -445,6 +461,8 @@ RTMP_SetupStream(RTMP *r, -+ AVal *flashVer, -+ AVal *subscribepath, -+ AVal *usherToken, -++ AVal *WeebToken, -++ AVal *ccomm, -+ int dStart, -+ int dStop, int bLiveStream, long int timeout) -+ { -+@@ -467,6 +485,8 @@ RTMP_SetupStream(RTMP *r, -+ RTMP_Log(RTMP_LOGDEBUG, "subscribepath : %s", subscribepath->av_val); -+ if (usherToken && usherToken->av_val) -+ RTMP_Log(RTMP_LOGDEBUG, "NetStream.Authenticate.UsherToken : %s", usherToken->av_val); -++ if (WeebToken && WeebToken->av_val) -++ RTMP_Log(RTMP_LOGDEBUG, "WeebToken: %s", WeebToken->av_val); -+ if (flashVer && flashVer->av_val) -+ RTMP_Log(RTMP_LOGDEBUG, "flashVer : %s", flashVer->av_val); -+ if (dStart > 0) -+@@ -515,6 +535,10 @@ RTMP_SetupStream(RTMP *r, -+ r->Link.subscribepath = *subscribepath; -+ if (usherToken && usherToken->av_len) -+ r->Link.usherToken = *usherToken; -++ if (WeebToken && WeebToken->av_len) -++ r->Link.WeebToken = *WeebToken; -++ if (ccomm && ccomm->av_len) -++ r->Link.ccomm = *ccomm; -+ r->Link.seekTime = dStart; -+ r->Link.stopTime = dStop; -+ if (bLiveStream) -+@@ -572,14 +596,24 @@ static struct urlopt { -+ "Stream is live, no seeking possible" }, -+ { AVC("subscribe"), OFF(Link.subscribepath), OPT_STR, 0, -+ "Stream to subscribe to" }, -+- { AVC("jtv"), OFF(Link.usherToken), OPT_STR, 0, -+- "Justin.tv authentication token" }, -+- { AVC("token"), OFF(Link.token), OPT_STR, 0, -++ { AVC("jtv"), OFF(Link.usherToken), OPT_STR, 0, -++ "Justin.tv authentication token"}, -++ { AVC("weeb"), OFF(Link.WeebToken), OPT_STR, 0, -++ "Weeb.tv authentication token"}, -++ { AVC("token"), OFF(Link.token), OPT_STR, 0, -+ "Key for SecureToken response" }, -++ { AVC("ccommand"), OFF(Link.ccomm), OPT_STR, 0, -++ "Send custom command before play" }, -+ { AVC("swfVfy"), OFF(Link.lFlags), OPT_BOOL, RTMP_LF_SWFV, -+ "Perform SWF Verification" }, -+ { AVC("swfAge"), OFF(Link.swfAge), OPT_INT, 0, -+ "Number of days to use cached SWF hash" }, -++#ifdef CRYPTO -++ { AVC("swfsize"), OFF(Link.swfSize), OPT_INT, 0, -++ "Size of the decompressed SWF file"}, -++ { AVC("swfhash"), OFF(Link.swfHash), OPT_STR, 0, -++ "SHA256 hash of the decompressed SWF file"}, -++#endif -+ { AVC("start"), OFF(Link.seekTime), OPT_INT, 0, -+ "Stream start position in milliseconds" }, -+ { AVC("stop"), OFF(Link.stopTime), OPT_INT, 0, -+@@ -685,6 +719,9 @@ parseAMF(AMFObject *obj, AVal *av, int *depth) -+ case 'O': -+ prop.p_type = AMF_OBJECT; -+ break; -++ case 'Z': -++ prop.p_type = AMF_NULL; -++ break; -+ default: -+ return -1; -+ } -+@@ -722,7 +759,7 @@ int RTMP_SetOpt(RTMP *r, const AVal *opt, AVal *arg) -+ *aptr = *arg; } -+ break; -+ case OPT_INT: { -+- long l = strtol(arg->av_val, NULL, 0); -++ long l = strtol(arg->av_val, NULL, 10); -+ *(int *)v = l; } -+ break; -+ case OPT_BOOL: { -+@@ -767,7 +804,7 @@ int RTMP_SetupURL(RTMP *r, char *url) -+ if (!ret) -+ return ret; -+ r->Link.port = port; -+- r->Link.playpath = r->Link.playpath0; -++ r->Link.playpath = AVcopy(r->Link.playpath0); -+ -+ while (ptr) { -+ *ptr++ = '\0'; -+@@ -844,9 +881,16 @@ int RTMP_SetupURL(RTMP *r, char *url) -+ } -+ -+ #ifdef CRYPTO -+- if ((r->Link.lFlags & RTMP_LF_SWFV) && r->Link.swfUrl.av_len) -+- RTMP_HashSWF(r->Link.swfUrl.av_val, &r->Link.SWFSize, -+- (unsigned char *)r->Link.SWFHash, r->Link.swfAge); -++ RTMP_Log(RTMP_LOGDEBUG, "Khalsa: %d %d %s", r->Link.swfSize, r->Link.swfHash.av_len, r->Link.swfHash.av_val); -++ if (r->Link.swfSize && r->Link.swfHash.av_len) -++ { -++ int i, j = 0; -++ for (i = 0; i < r->Link.swfHash.av_len; i += 2) -++ r->Link.SWFHash[j++] = (HEX2BIN(r->Link.swfHash.av_val[i]) << 4) | HEX2BIN(r->Link.swfHash.av_val[i + 1]); -++ r->Link.SWFSize = (uint32_t) r->Link.swfSize; -++ } -++ else if ((r->Link.lFlags & RTMP_LF_SWFV) && r->Link.swfUrl.av_len) -++ RTMP_HashSWF(r->Link.swfUrl.av_val, &r->Link.SWFSize, (unsigned char *) r->Link.SWFHash, r->Link.swfAge); -+ #endif -+ -+ SocksSetup(r, &r->Link.sockshost); -+@@ -949,6 +993,8 @@ RTMP_Connect0(RTMP *r, struct sockaddr * service) -+ } -+ -+ setsockopt(r->m_sb.sb_socket, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on)); -++ if (r->Link.protocol & RTMP_FEATURE_HTTP) -++ setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof (on)); -+ -+ return TRUE; -+ } -+@@ -1399,41 +1445,96 @@ ReadN(RTMP *r, char *buffer, int n) -+ ptr = buffer; -+ while (n > 0) -+ { -+- int nBytes = 0, nRead; -++ int nBytes = 0, nRead, status = 0, retries = 0; -+ if (r->Link.protocol & RTMP_FEATURE_HTTP) -+ { -+- int refill = 0; -+- while (!r->m_resplen) -+- { -+- int ret; -+- if (r->m_sb.sb_size < 13 || refill) -+- { -+- if (!r->m_unackd) -+- HTTP_Post(r, RTMPT_IDLE, "", 1); -+- if (RTMPSockBuf_Fill(&r->m_sb) < 1) -+- { -+- if (!r->m_sb.sb_timedout) -+- RTMP_Close(r); -+- return 0; -+- } -+- } -+- if ((ret = HTTP_read(r, 0)) == -1) -+- { -+- RTMP_Log(RTMP_LOGDEBUG, "%s, No valid HTTP response found", __FUNCTION__); -+- RTMP_Close(r); -+- return 0; -+- } -+- else if (ret == -2) -++ while (!r->m_resplen) -++ { -++ /* Refill if socket buffer is empty */ -++ if (!r->m_sb.sb_size) -+ { -+- refill = 1; -++ if (retries > 30) -++ { -++ RTMP_Close(r); -++ return 0; -++ } -++ -++ if (!r->m_unackd) -++ { -++ if (retries > 0) -++ { -++ HTTP_Post(r, RTMPT_IDLE, "", 1); -++ r->m_unackd = TRUE; -++ } -++ retries++; -++ -++ if (!r->m_bPlaying) -++ sleep(.25); -++ } -++ -++ RTMP_Log(RTMP_LOGDEBUG, "Trying to fill HTTP buffer, Retries: %d", retries); -++ status = RTMPSockBuf_Fill(&r->m_sb); -++ /* Reconnect socket when closed by some moronic servers after -++ * every HTTP data packet */ -++ if (status < 1) -++ { -++ /* Close connection on connection reset */ -++ if (status == -1) -++ { -++ RTMP_Close(r); -++ return 0; -++ } -++ -++ RTMP_Log(RTMP_LOGDEBUG, "Reconnecting socket, Status: %d", status); -++ if (ConnectSocket(r)) -++ { -++ HTTP_Post(r, RTMPT_IDLE, "", 1); -++ r->m_unackd = TRUE; -++ retries++; -++ } -++ else -++ { -++ RTMP_Close(r); -++ return 0; -++ } -++ } -+ } -+- else -++ -++ RTMP_Log(RTMP_LOGDEBUG, "Trying to read HTTP response, Bytes Available: %d", r->m_sb.sb_size); -++ status = HTTP_read(r, 0); -++ if (status == -1) -+ { -+- refill = 0; -++ RTMP_Log(RTMP_LOGDEBUG, "%s, No valid HTTP response found", __FUNCTION__); -++ RTMP_Close(r); -++ return 0; -+ } -+- } -+- if (r->m_resplen && !r->m_sb.sb_size) -+- RTMPSockBuf_Fill(&r->m_sb); -++ else if (status == -2) -++ { -++ if (RTMPSockBuf_Fill(&r->m_sb) < 1) -++ if (!r->m_sb.sb_timedout) -++ { -++ RTMP_Close(r); -++ return 0; -++ } -++ } -++ else if (status == -3) -++ { -++ RTMP_Close(r); -++ return 0; -++ } -++ else -++ r->m_unackd = FALSE; -++ } -++ -++ /* Refill when there is still some data to be read and socket buffer -++ * is empty */ -++ if (r->m_resplen && (!r->m_sb.sb_size)) -++ { -++ if (RTMPSockBuf_Fill(&r->m_sb) < 1) -++ if (!r->m_sb.sb_timedout) -++ RTMP_Close(r); -++ } -++ -+ avail = r->m_sb.sb_size; -+ if (avail > r->m_resplen) -+ avail = r->m_resplen; -+@@ -1460,10 +1561,11 @@ ReadN(RTMP *r, char *buffer, int n) -+ r->m_sb.sb_size -= nRead; -+ nBytes = nRead; -+ r->m_nBytesIn += nRead; -+- if (r->m_bSendCounter -+- && r->m_nBytesIn > ( r->m_nBytesInSent + r->m_nClientBW / 10)) -+- if (!SendBytesReceived(r)) -+- return FALSE; -++ if (r->m_nBytesIn > 0xF0000000) -++ r->m_nBytesIn -= 0xF0000000; -++ if (r->m_bSendCounter && (r->m_nBytesIn > (r->m_nBytesInSent + r->m_nClientBW / 10))) -++ if (!SendBytesReceived(r)) -++ return FALSE; -+ } -+ /*RTMP_Log(RTMP_LOGDEBUG, "%s: %d bytes\n", __FUNCTION__, nBytes); */ -+ #ifdef _DEBUG -+@@ -1474,7 +1576,8 @@ ReadN(RTMP *r, char *buffer, int n) -+ { -+ RTMP_Log(RTMP_LOGDEBUG, "%s, RTMP socket closed by peer", __FUNCTION__); -+ /*goto again; */ -+- RTMP_Close(r); -++ if (!r->m_sb.sb_timedout) -++ RTMP_Close(r); -+ break; -+ } -+ -+@@ -1499,6 +1602,7 @@ static int -+ WriteN(RTMP *r, const char *buffer, int n) -+ { -+ const char *ptr = buffer; -++ char *ConnectPacket = 0; -+ #ifdef CRYPTO -+ char *encrypted = 0; -+ char buf[RTMP_BUFFER_CACHE_SIZE]; -+@@ -1514,6 +1618,15 @@ WriteN(RTMP *r, const char *buffer, int n) -+ } -+ #endif -+ -++ if (r->Link.ConnectPacket) -++ { -++ char *ConnectPacket = malloc(r->Link.HandshakeResponse.av_len + n); -++ memcpy(ConnectPacket, r->Link.HandshakeResponse.av_val, r->Link.HandshakeResponse.av_len); -++ memcpy(ConnectPacket + r->Link.HandshakeResponse.av_len, ptr, n); -++ ptr = ConnectPacket; -++ n += r->Link.HandshakeResponse.av_len; -++ } -++ -+ while (n > 0) -+ { -+ int nBytes; -+@@ -1550,6 +1663,14 @@ WriteN(RTMP *r, const char *buffer, int n) -+ free(encrypted); -+ #endif -+ -++ if (r->Link.ConnectPacket) -++ { -++ if (r->Link.HandshakeResponse.av_val) -++ free(r->Link.HandshakeResponse.av_val); -++ free(ConnectPacket); -++ r->Link.ConnectPacket = FALSE; -++ } -++ -+ return n == 0; -+ } -+ -+@@ -1579,6 +1700,9 @@ SendConnectPacket(RTMP *r, RTMPPacket *cp) -+ char pbuf[4096], *pend = pbuf + sizeof(pbuf); -+ char *enc; -+ -++ if (r->Link.CombineConnectPacket) -++ r->Link.ConnectPacket = TRUE; -++ -+ if (cp) -+ return RTMP_SendPacket(r, cp, TRUE); -+ -+@@ -1627,7 +1751,7 @@ SendConnectPacket(RTMP *r, RTMPPacket *cp) -+ enc = AMF_EncodeNamedBoolean(enc, pend, &av_fpad, FALSE); -+ if (!enc) -+ return FALSE; -+- enc = AMF_EncodeNamedNumber(enc, pend, &av_capabilities, 15.0); -++ enc = AMF_EncodeNamedNumber(enc, pend, &av_capabilities, 239.0); -+ if (!enc) -+ return FALSE; -+ enc = AMF_EncodeNamedNumber(enc, pend, &av_audioCodecs, r->m_fAudioCodecs); -+@@ -1791,7 +1915,7 @@ SendUsherToken(RTMP *r, AVal *usherToken) -+ packet.m_hasAbsTimestamp = 0; -+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE; -+ -+- RTMP_Log(RTMP_LOGDEBUG, "UsherToken: %s", usherToken->av_val); -++ RTMP_Log(RTMP_LOGDEBUG, "UsherToken: %.*s", usherToken->av_len, usherToken->av_val); -+ enc = packet.m_body; -+ enc = AMF_EncodeString(enc, pend, &av_NetStream_Authenticate_UsherToken); -+ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -+@@ -1934,6 +2058,26 @@ SendPublish(RTMP *r) -+ return RTMP_SendPacket(r, &packet, TRUE); -+ } -+ -++static int -++SendDynamicPublish(RTMP *r, double publishId) -++{ -++ char pbuf[1024], *pend = pbuf + sizeof (pbuf), *enc; -++ AVal av_command, av_publishId; -++ -++ enc = pbuf; -++ enc = AMF_EncodeString(enc, pend, &av_publish); -++ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -++ *enc++ = AMF_NULL; -++ av_publishId.av_val = malloc(128 * sizeof (char)); -++ av_publishId.av_len = sprintf(av_publishId.av_val, "%.0f", publishId); -++ enc = AMF_EncodeString(enc, pend, &av_publishId); -++ enc = AMF_EncodeString(enc, pend, &av_live); -++ av_command.av_val = pbuf; -++ av_command.av_len = enc - pbuf; -++ -++ return SendInvoke(r, &av_command, FALSE); -++} -++ -+ SAVC(deleteStream); -+ -+ static int -+@@ -2097,6 +2241,7 @@ SendBytesReceived(RTMP *r) -+ } -+ -+ SAVC(_checkbw); -++SAVC(checkBandwidth); -+ -+ static int -+ SendCheckBW(RTMP *r) -+@@ -2114,7 +2259,7 @@ SendCheckBW(RTMP *r) -+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE; -+ -+ enc = packet.m_body; -+- enc = AMF_EncodeString(enc, pend, &av__checkbw); -++ enc = AMF_EncodeString(enc, pend, &av_checkBandwidth); -+ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -+ *enc++ = AMF_NULL; -+ -+@@ -2221,10 +2366,8 @@ SendPlay(RTMP *r) -+ enc = AMF_EncodeNumber(enc, pend, -1000.0); -+ else -+ { -+- if (r->Link.seekTime > 0.0) -+- enc = AMF_EncodeNumber(enc, pend, r->Link.seekTime); /* resume from here */ -+- else -+- enc = AMF_EncodeNumber(enc, pend, 0.0); /*-2000.0);*/ /* recorded as default, -2000.0 is not reliable since that freezes the player if the stream is not found */ -++ if (r->Link.seekTime > 0.0 || r->Link.stopTime) -++ enc = AMF_EncodeNumber(enc, pend, r->Link.seekTime); /* resume from here */ -+ } -+ if (!enc) -+ return FALSE; -+@@ -2340,7 +2483,7 @@ RTMP_SendCtrl(RTMP *r, short nType, unsigned int nObject, unsigned int nTime) -+ int nSize; -+ char *buf; -+ -+- RTMP_Log(RTMP_LOGDEBUG, "sending ctrl. type: 0x%04x", (unsigned short)nType); -++ RTMP_Log(RTMP_LOGDEBUG, "sending ctrl, type: 0x%04x", (unsigned short)nType); -+ -+ packet.m_nChannel = 0x02; /* control channel (ping) */ -+ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM; -+@@ -2372,8 +2515,8 @@ RTMP_SendCtrl(RTMP *r, short nType, unsigned int nObject, unsigned int nTime) -+ } -+ else if (nType == 0x1A) -+ { -+- *buf = nObject & 0xff; -+- } -++ *buf = nObject & 0xff; -++ } -+ else -+ { -+ if (nSize > 2) -+@@ -2873,6 +3016,7 @@ PublisherAuth(RTMP *r, AVal *description) -+ #endif -+ -+ -++SAVC(onBWCheck); -+ SAVC(onBWDone); -+ SAVC(onFCSubscribe); -+ SAVC(onFCUnsubscribe); -+@@ -2885,24 +3029,25 @@ SAVC(level); -+ SAVC(description); -+ SAVC(onStatus); -+ SAVC(playlist_ready); -++SAVC(cps); -++SAVC(disneyToken); -++SAVC(getStreamLength); -++SAVC(sendStatus); -++SAVC(verifyClient); -+ static const AVal av_NetStream_Failed = AVC("NetStream.Failed"); -+ static const AVal av_NetStream_Play_Failed = AVC("NetStream.Play.Failed"); -+-static const AVal av_NetStream_Play_StreamNotFound = -+-AVC("NetStream.Play.StreamNotFound"); -+-static const AVal av_NetConnection_Connect_InvalidApp = -+-AVC("NetConnection.Connect.InvalidApp"); -++static const AVal av_NetStream_Play_StreamNotFound = AVC("NetStream.Play.StreamNotFound"); -++static const AVal av_NetConnection_Connect_InvalidApp = AVC("NetConnection.Connect.InvalidApp"); -+ static const AVal av_NetStream_Play_Start = AVC("NetStream.Play.Start"); -+ static const AVal av_NetStream_Play_Complete = AVC("NetStream.Play.Complete"); -+ static const AVal av_NetStream_Play_Stop = AVC("NetStream.Play.Stop"); -+ static const AVal av_NetStream_Seek_Notify = AVC("NetStream.Seek.Notify"); -+ static const AVal av_NetStream_Pause_Notify = AVC("NetStream.Pause.Notify"); -+-static const AVal av_NetStream_Play_PublishNotify = -+-AVC("NetStream.Play.PublishNotify"); -+-static const AVal av_NetStream_Play_UnpublishNotify = -+-AVC("NetStream.Play.UnpublishNotify"); -++static const AVal av_NetStream_Play_PublishNotify = AVC("NetStream.Play.PublishNotify"); -++static const AVal av_NetStream_Play_UnpublishNotify = AVC("NetStream.Play.UnpublishNotify"); -+ static const AVal av_NetStream_Publish_Start = AVC("NetStream.Publish.Start"); -+-static const AVal av_NetConnection_Connect_Rejected = -+-AVC("NetConnection.Connect.Rejected"); -++static const AVal av_NetConnection_Connect_Rejected = AVC("NetConnection.Connect.Rejected"); -++static const AVal av_NetConnection_confStream = AVC("NetConnection.confStream"); -+ -+ /* Returns 0 for OK/Failed/error, 1 for 'Stop or Complete' */ -+ static int -+@@ -2912,6 +3057,11 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize) -+ AVal method; -+ double txn; -+ int ret = 0, nRes; -++ char pbuf[512], *pend = pbuf + sizeof (pbuf), *enc, **params = NULL; -++ char *host = r->Link.hostname.av_len ? r->Link.hostname.av_val : ""; -++ char *pageUrl = r->Link.pageUrl.av_len ? r->Link.pageUrl.av_val : ""; -++ int param_count; -++ AVal av_Command, av_Response; -+ if (body[0] != 0x02) /* make sure it is a string method name we start with */ -+ { -+ RTMP_Log(RTMP_LOGWARNING, "%s, Sanity failed. no string method in invoke packet", -+@@ -2952,7 +3102,14 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize) -+ RTMP_Log(RTMP_LOGDEBUG, "%s, received result for method call <%s>", __FUNCTION__, -+ methodInvoked.av_val); -+ -+- if (AVMATCH(&methodInvoked, &av_connect)) -++ if ((r->Link.dynamicPublish == TRUE) && AVMATCH(&methodInvoked, &r->Link.dynamicCommand)) -++ { -++ r->Link.dynamicPublish = FALSE; -++ r->Link.publishId = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3)); -++ RTMP_Log(RTMP_LOGDEBUG, "server returned dynamic publish id: %.0f", r->Link.publishId); -++ RTMP_SendCreateStream(r); -++ } -++ else if (AVMATCH(&methodInvoked, &av_connect)) -+ { -+ if (r->Link.token.av_len) -+ { -+@@ -2973,46 +3130,360 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize) -+ RTMP_SendServerBW(r); -+ RTMP_SendCtrl(r, 3, 0, 300); -+ } -+- RTMP_SendCreateStream(r); -++ if (r->Link.ccomm.av_len) -++ { -++ param_count = strsplit(r->Link.ccomm.av_val, FALSE, ';', ¶ms); -++ if ((param_count > 1) && (strcasecmp(params[1], "TRUE") == 0)) -++ SendCommand(r, params[0], TRUE); -++ else -++ SendCommand(r, params[0], FALSE); -++ if ((param_count > 2) && (strcasecmp(params[2], "TRUE") == 0)) -++ { -++ RTMP_Log(RTMP_LOGDEBUG, "overriding inbuilt dynamic publish command with -K (ccommand) switch"); -++ r->Link.dynamicPublish = TRUE; -++ r->Link.dynamicCommand.av_val = params[0]; -++ r->Link.dynamicCommand.av_len = strlen(params[0]); -++ } -++ else -++ { -++ RTMP_Log(RTMP_LOGDEBUG, "overriding inbuilt site specific authentication with -K (ccommand) switch"); -++ r->Link.dynamicPublish = FALSE; -++ RTMP_SendCreateStream(r); -++ } -++ } -++ else if (strstr(host, "3dbuzz.com") || strstr(pageUrl, "3dbuzz.com")) -++ { -++ AVal r1, r3; -++ AVal av_r1 = AVC("r1"); -++ AVal av_r3 = AVC("r3"); -++ AVal r1_key = AVC("4V?c6k7Y`(6~rMjp6S6!xT04]8m$g2"); -++ AVal r3_key = AVC("aB`d^+8?9;36]Lw2#rg?PDMcX?lCw2"); -++ TransformRot13(&obj, &av_r1, &r1); -++ TransformRot13(&obj, &av_r3, &r3); -++ if (r1.av_val && r3.av_val) -++ { -++ AVal av_qq = AVC("qq"); -++ AVal av_tos = AVC("http://www.3dbuzz.com/home/tos"); -++ AVal av_warning = AVC("Stream capturing is a violation of our terms, and may result in immediate cancellation of your account without refund"); -++ AVal r1_response; -++ -++ RTMP_Log(RTMP_LOGDEBUG, "3DBuzz SecureToken r1 request - %.*s", r1.av_len, r1.av_val); -++ RTMP_Log(RTMP_LOGDEBUG, "3DBuzz SecureToken r3 request - %.*s", r3.av_len, r3.av_val); -++ DecodeTEA(&r1_key, &r1); -++ DecodeTEA(&r3_key, &r3); -++ r1_response = TeaEncrypt(&av_tos, &r1); -++ RTMP_Log(RTMP_LOGDEBUG, "3DBuzz SecureToken r1 response - %.*s", r1_response.av_len, r1_response.av_val); -++ RTMP_Log(RTMP_LOGDEBUG, "3DBuzz SecureToken r3 response - %.*s", r3.av_len, r3.av_val); -++ -++ enc = pbuf; -++ enc = AMF_EncodeString(enc, pend, &av_qq); -++ enc = AMF_EncodeNumber(enc, pend, 0); -++ *enc++ = AMF_NULL; -++ enc = AMF_EncodeString(enc, pend, &r3); -++ enc = AMF_EncodeString(enc, pend, &av_tos); -++ enc = AMF_EncodeString(enc, pend, &r1_response); -++ enc = AMF_EncodeString(enc, pend, &av_warning); -++ av_Command.av_val = pbuf; -++ av_Command.av_len = enc - pbuf; -++ SendInvoke(r, &av_Command, FALSE); -++ } -+ -+- if (!(r->Link.protocol & RTMP_FEATURE_WRITE)) -+- { -+- /* Authenticate on Justin.tv legacy servers before sending FCSubscribe */ -+- if (r->Link.usherToken.av_len) -+- SendUsherToken(r, &r->Link.usherToken); -+- /* Send the FCSubscribe if live stream or if subscribepath is set */ -+- if (r->Link.subscribepath.av_len) -+- SendFCSubscribe(r, &r->Link.subscribepath); -+- else if (r->Link.lFlags & RTMP_LF_LIVE) -+- SendFCSubscribe(r, &r->Link.playpath); -+- } -+- } -++ RTMP_SendCreateStream(r); -++ } -++ else if (strstr(pageUrl, "cam4")) -++ { -++ AMFObject obj2, response; -++ AMFObjectProperty p; -++ AVal Host, ID, IP, av_ChallengeResponse; -++ AVal av_receiveRTMPResponse = AVC("receiveRTMPResponse"); -++ AVal av_client = AVC("client"); -++ AVal av_result = AVC("result"); -++ char ChallengeResponse[16] = {0}; -++ SAVC(application); -++ SAVC(Host); -++ SAVC(ID); -++ SAVC(IP); -++ -++ AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &obj2); -++ if (RTMP_FindFirstMatchingProperty(&obj2, &av_application, &p)) -++ { -++ RTMP_Log(RTMP_LOGDEBUG, "sending cam4 authentication"); -++ AMFProp_GetObject(&p, &obj2); -++ RTMP_FindFirstMatchingProperty(&obj2, &av_Host, &p); -++ AMFProp_GetString(&p, &Host); -++ RTMP_FindFirstMatchingProperty(&obj2, &av_ID, &p); -++ AMFProp_GetString(&p, &ID); -++ RTMP_FindFirstMatchingProperty(&obj2, &av_IP, &p); -++ AMFProp_GetString(&p, &IP); -++ RTMP_Log(RTMP_LOGDEBUG, "Cam4 Host: %.*s", Host.av_len, Host.av_val); -++ RTMP_Log(RTMP_LOGDEBUG, "Cam4 ID : %.*s", ID.av_len, ID.av_val); -++ RTMP_Log(RTMP_LOGDEBUG, "Cam4 IP : %.*s", IP.av_len, IP.av_val); -++ snprintf(ChallengeResponse, 15, "%d", Host.av_len + ID.av_len + IP.av_len); -++ av_ChallengeResponse.av_val = ChallengeResponse; -++ av_ChallengeResponse.av_len = strlen(av_ChallengeResponse.av_val); -++ AMFProp_SetName(&p, &av_client); -++ AMFProp_SetString(&p, &ID); -++ AMF_AddProp(&response, &p); -++ AMFProp_SetName(&p, &av_result); -++ AMFProp_SetString(&p, &av_ChallengeResponse); -++ AMF_AddProp(&response, &p); -++ -++ enc = pbuf; -++ enc = AMF_EncodeString(enc, pend, &av_receiveRTMPResponse); -++ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -++ *enc++ = AMF_NULL; -++ enc = AMF_Encode(&response, enc, pend); -++ enc = AMF_EncodeBoolean(enc, pend, TRUE); -++ av_Response.av_val = pbuf; -++ av_Response.av_len = enc - pbuf; -++ -++ AMF_Decode(&obj, av_Response.av_val, av_Response.av_len, FALSE); -++ AMF_Dump(&obj); -++ SendInvoke(r, &av_Response, TRUE); -++ } -++ -++ RTMP_SendCreateStream(r); -++ } -++ else if ((strstr(host, "highwebmedia.com") || strstr(pageUrl, "chaturbate.com")) -++ && (!strstr(host, "origin"))) -++ { -++ AVal av_ModelName; -++ SAVC(CheckPublicStatus); -++ -++ if (strlen(pageUrl) > 7) -++ { -++ strsplit(pageUrl + 7, FALSE, '/', ¶ms); -++ av_ModelName.av_val = params[1]; -++ av_ModelName.av_len = strlen(params[1]); -++ -++ enc = pbuf; -++ enc = AMF_EncodeString(enc, pend, &av_CheckPublicStatus); -++ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -++ *enc++ = AMF_NULL; -++ enc = AMF_EncodeString(enc, pend, &av_ModelName); -++ av_Command.av_val = pbuf; -++ av_Command.av_len = enc - pbuf; -++ -++ SendInvoke(r, &av_Command, FALSE); -++ } -++ else -++ { -++ RTMP_Log(RTMP_LOGERROR, "you must specify the pageUrl"); -++ RTMP_Close(r); -++ } -++ } -++ else if (strstr(host, "featve.com") || strstr(pageUrl, "featve.com")) -++ { -++ AVal av_auth = AVC("yes"); -++ SAVC(youCannotPlayMe); -++ -++ enc = pbuf; -++ enc = AMF_EncodeString(enc, pend, &av_youCannotPlayMe); -++ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -++ *enc++ = AMF_NULL; -++ enc = AMF_EncodeString(enc, pend, &av_auth); -++ av_Command.av_val = pbuf; -++ av_Command.av_len = enc - pbuf; -++ SendInvoke(r, &av_Command, FALSE); -++ -++ RTMP_SendCreateStream(r); -++ } -++ else if (strstr(host, "tv-stream.to") || strstr(pageUrl, "tv-stream.to")) -++ { -++ static char auth[] = {'h', 0xC2, 0xA7, '4', 'j', 'h', 'H', '4', '3', 'd'}; -++ AVal av_auth; -++ SAVC(requestAccess); -++ av_auth.av_val = auth; -++ av_auth.av_len = sizeof (auth); -++ -++ enc = pbuf; -++ enc = AMF_EncodeString(enc, pend, &av_requestAccess); -++ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -++ *enc++ = AMF_NULL; -++ enc = AMF_EncodeString(enc, pend, &av_auth); -++ av_Command.av_val = pbuf; -++ av_Command.av_len = enc - pbuf; -++ SendInvoke(r, &av_Command, FALSE); -++ -++ SendCommand(r, "getConnectionCount", FALSE); -++ SendGetStreamLength(r); -++ RTMP_SendCreateStream(r); -++ } -++ else if (r->Link.WeebToken.av_len) -++ { -++ AVal av_Token, av_Username, av_Password; -++ SAVC(determineAccess); -++ -++ param_count = strsplit(r->Link.WeebToken.av_val, FALSE, ';', ¶ms); -++ if (param_count >= 1) -++ { -++ av_Token.av_val = params[0]; -++ av_Token.av_len = strlen(params[0]); -++ } -++ if (param_count >= 2) -++ { -++ av_Username.av_val = params[1]; -++ av_Username.av_len = strlen(params[1]); -++ } -++ if (param_count >= 3) -++ { -++ av_Password.av_val = params[2]; -++ av_Password.av_len = strlen(params[2]); -++ } -++ -++ enc = pbuf; -++ enc = AMF_EncodeString(enc, pend, &av_determineAccess); -++ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -++ *enc++ = AMF_NULL; -++ enc = AMF_EncodeString(enc, pend, &av_Token); -++ enc = AMF_EncodeString(enc, pend, &av_Username); -++ enc = AMF_EncodeString(enc, pend, &av_Password); -++ av_Command.av_val = pbuf; -++ av_Command.av_len = enc - pbuf; -++ -++ RTMP_Log(RTMP_LOGDEBUG, "WeebToken: %s", r->Link.WeebToken.av_val); -++ SendInvoke(r, &av_Command, FALSE); -++ } -++ else if (strstr(host, "wfctv.com") || strstr(pageUrl, "wfctv.com")) -++ { -++ AVal av_auth1 = AVC("zoivid"); -++ AVal av_auth2 = AVC("yePi4jee"); -++ SAVC(stream_login); -++ -++ enc = pbuf; -++ enc = AMF_EncodeString(enc, pend, &av_stream_login); -++ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -++ *enc++ = AMF_NULL; -++ enc = AMF_EncodeString(enc, pend, &av_auth1); -++ enc = AMF_EncodeString(enc, pend, &av_auth2); -++ av_Command.av_val = pbuf; -++ av_Command.av_len = enc - pbuf; -++ SendInvoke(r, &av_Command, FALSE); -++ -++ RTMP_SendCreateStream(r); -++ } -++ else if (strstr(host, "pc3oot.us.to")) -++ { -++ SendCommand(r, "UIUIUINASOWAS", TRUE); -++ SendGetStreamLength(r); -++ RTMP_SendCreateStream(r); -++ } -++ else if (strstr(host, "streamscene.cc") || strstr(pageUrl, "streamscene.cc") -++ || strstr(host, "tsboard.tv") || strstr(pageUrl, "teamstream.in") -++ || strstr(host, "hdstreams.tv") || strstr(pageUrl, "teamstream.to") -++ || strstr(pageUrl, "istreams.to")) -++ { -++ SendCommand(r, "r", FALSE); -++ SendGetStreamLength(r); -++ RTMP_SendCreateStream(r); -++ } -++ else if (strstr(pageUrl, "axcast.com")) -++ { -++ SendCommand(r, "requestData", FALSE); -++ RTMP_SendCreateStream(r); -++ } -++ else if (strstr(pageUrl, "dhmediahosting.com")) -++ { -++ SendCommand(r, "netStreamEnable", FALSE); -++ RTMP_SendCreateStream(r); -++ } -++ else if (strstr(pageUrl, "ezcast.tv")) -++ { -++ SendCommand(r, "iUsteJaSakamCarevataKerka", TRUE); -++ RTMP_SendCreateStream(r); -++ } -++ else if (strstr(pageUrl, "janjua.tv")) -++ { -++ SendCommand(r, "soLagaDaSeStoriAga", TRUE); -++ RTMP_SendCreateStream(r); -++ } -++ else if (strstr(pageUrl, "liveflash.tv")) -++ { -++ char *command = "kaskatijaEkonomista"; -++ r->Link.dynamicPublish = TRUE; -++ r->Link.dynamicCommand.av_val = command; -++ r->Link.dynamicCommand.av_len = strlen(command); -++ SendCommand(r, command, TRUE); -++ } -++ else if (strstr(pageUrl, "mips.tv") || strstr(pageUrl, "mipsplayer.com")) -++ { -++ char *command = "gaolVanusPobeleVoKosata"; -++ r->Link.dynamicPublish = TRUE; -++ r->Link.dynamicCommand.av_val = command; -++ r->Link.dynamicCommand.av_len = strlen(command); -++ SendCommand(r, command, TRUE); -++ } -++ else if (strstr(pageUrl, "streamify.tv")) -++ { -++ SendCommand(r, "keGoVidishStambolSoseBardovci", TRUE); -++ RTMP_SendCreateStream(r); -++ } -++ else if (strstr(pageUrl, "ucaster.eu")) -++ { -++ SendCommand(r, "vujkoMiLazarBarakovOdMonospitovo", TRUE); -++ RTMP_SendCreateStream(r); -++ } -++ else if (strstr(pageUrl, "yukons.net")) -++ { -++ SendCommand(r, "trxuwaaLahRKnaechb", TRUE); -++ RTMP_SendCreateStream(r); -++ } -++ else if (strstr(pageUrl, "yycast.com")) -++ { -++ SendCommand(r, "trajkoProkopiev", TRUE); -++ RTMP_SendCreateStream(r); -++ } -++ else if (strstr(pageUrl, "zenex.tv")) -++ { -++ SendCommand(r, "goVideStambolSoseBardovci", TRUE); -++ RTMP_SendCreateStream(r); -++ } -++ else -++ RTMP_SendCreateStream(r); -++ } -+ else if (AVMATCH(&methodInvoked, &av_createStream)) -+- { -+- r->m_stream_id = (int)AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3)); -++ { -++ r->m_stream_id = (int) AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3)); -+ -+- if (r->Link.protocol & RTMP_FEATURE_WRITE) -+- { -+- SendPublish(r); -+- } -+- else -+- { -+- if (r->Link.lFlags & RTMP_LF_PLST) -+- SendPlaylist(r); -+- SendPlay(r); -+- RTMP_SendCtrl(r, 3, r->m_stream_id, r->m_nBufferMS); -+- } -+- } -++ if (!(r->Link.protocol & RTMP_FEATURE_WRITE)) -++ { -++ /* Authenticate on Justin.tv legacy servers before sending FCSubscribe */ -++ if (r->Link.usherToken.av_len) -++ SendUsherToken(r, &r->Link.usherToken); -++ if (r->Link.publishId > 0) -++ { -++ RTMP_Log(RTMP_LOGDEBUG, "sending dynamic publish id: %.0f", r->Link.publishId); -++ SendDynamicPublish(r, r->Link.publishId); -++ } -++ /* Send the FCSubscribe if live stream or if subscribepath is set */ -++ if (r->Link.subscribepath.av_len) -++ SendFCSubscribe(r, &r->Link.subscribepath); -++ else if ((r->Link.lFlags & RTMP_LF_LIVE) && (!r->Link.WeebToken.av_len)) -++ SendFCSubscribe(r, &r->Link.playpath); -++ } -++ -++ if (r->Link.protocol & RTMP_FEATURE_WRITE) -++ { -++ SendPublish(r); -++ } -++ else -++ { -++ if (r->Link.lFlags & RTMP_LF_PLST) -++ SendPlaylist(r); -++ SendPlay(r); -++ RTMP_SendCtrl(r, 3, r->m_stream_id, r->m_nBufferMS); -++ } -++ } -+ else if (AVMATCH(&methodInvoked, &av_play) || -+- AVMATCH(&methodInvoked, &av_publish)) -+- { -+- r->m_bPlaying = TRUE; -+- } -++ AVMATCH(&methodInvoked, &av_publish)) -++ { -++ r->m_bPlaying = TRUE; -++ } -+ free(methodInvoked.av_val); -+ } -+ else if (AVMATCH(&method, &av_onBWDone)) -+ { -+- if (!r->m_nBWCheckCounter) -++ if (!r->m_nBWCheckCounter) -+ SendCheckBW(r); -+ } -+ else if (AVMATCH(&method, &av_onFCSubscribe)) -+@@ -3036,21 +3507,22 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize) -+ { -+ int i; -+ for (i = 0; i < r->m_numCalls; i++) -+- if (AVMATCH(&r->m_methodCalls[i].name, &av__checkbw)) -+- { -+- AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE); -+- break; -+- } -++ if (AVMATCH(&r->m_methodCalls[i].name, &av__checkbw)) -++ { -++ AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE); -++ break; -++ } -+ } -+ else if (AVMATCH(&method, &av__error)) -+ { -++ int handled = FALSE; -+ #ifdef CRYPTO -+ AVal methodInvoked = {0}; -+ int i; -+ -+ if (r->Link.protocol & RTMP_FEATURE_WRITE) -+ { -+- for (i=0; im_numCalls; i++) -++ for (i = 0; i < r->m_numCalls; i++) -+ { -+ if (r->m_methodCalls[i].num == txn) -+ { -+@@ -3062,12 +3534,12 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize) -+ if (!methodInvoked.av_val) -+ { -+ RTMP_Log(RTMP_LOGDEBUG, "%s, received result id %f without matching request", -+- __FUNCTION__, txn); -++ __FUNCTION__, txn); -+ goto leave; -+ } -+ -+ RTMP_Log(RTMP_LOGDEBUG, "%s, received error for method call <%s>", __FUNCTION__, -+- methodInvoked.av_val); -++ methodInvoked.av_val); -+ -+ if (AVMATCH(&methodInvoked, &av_connect)) -+ { -+@@ -3086,34 +3558,96 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize) -+ goto leave; -+ } -+ } -+- } -+- else -+- { -+- RTMP_Log(RTMP_LOGERROR, "rtmp server sent error"); -++ handled = TRUE; -+ } -+ free(methodInvoked.av_val); -+-#else -+- RTMP_Log(RTMP_LOGERROR, "rtmp server sent error"); -+ #endif -++ double code = 0.0; -++ unsigned int parsedPort = 0; -++ AMFObject obj2; -++ AMFObjectProperty p; -++ AVal redirect; -++ SAVC(ex); -++ SAVC(redirect); -++ -++ AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &obj2); -++ if (RTMP_FindFirstMatchingProperty(&obj2, &av_ex, &p)) -++ { -++ AMFProp_GetObject(&p, &obj2); -++ if (RTMP_FindFirstMatchingProperty(&obj2, &av_code, &p)) -++ code = AMFProp_GetNumber(&p); -++ if (code == 302 && RTMP_FindFirstMatchingProperty(&obj2, &av_redirect, &p)) -++ { -++ AMFProp_GetString(&p, &redirect); -++ r->Link.redirected = TRUE; -++ -++ char *playpath = "//playpath"; -++ int len = redirect.av_len + strlen(playpath); -++ char *url = malloc(len + 1); -++ memcpy(url, redirect.av_val, redirect.av_len); -++ memcpy(url + redirect.av_len, playpath, strlen(playpath)); -++ url[len] = '\0'; -++ r->Link.tcUrl.av_val = url; -++ r->Link.tcUrl.av_len = redirect.av_len; -++ if (r->Link.lFlags & RTMP_LF_FTCU) -++ r->Link.lFlags ^= RTMP_LF_FTCU; -++ RTMP_ParseURL(url, &r->Link.protocol, &r->Link.hostname, &parsedPort, &r->Link.playpath0, &r->Link.app); -++ if (parsedPort) -++ r->Link.port = parsedPort; -++ } -++ } -++ if (r->Link.redirected) -++ { -++ handled = TRUE; -++ RTMP_Log(RTMP_LOGINFO, "rtmp server sent redirect"); -++ } -++ -++ if (!handled) -++ RTMP_Log(RTMP_LOGERROR, "rtmp server sent error"); -+ } -+ else if (AVMATCH(&method, &av_close)) -+ { -+- RTMP_Log(RTMP_LOGERROR, "rtmp server requested close"); -+- RTMP_Close(r); -++ if (r->Link.redirected) -++ { -++ r->Link.redirected = FALSE; -++ RTMP_Close(r); -++ RTMP_Log(RTMP_LOGINFO, "trying to connect with redirected url"); -++ if (r->Link.port == 0) -++ { -++ if (r->Link.protocol & RTMP_FEATURE_SSL) -++ r->Link.port = 443; -++ else if (r->Link.protocol & RTMP_FEATURE_HTTP) -++ r->Link.port = 80; -++ else -++ r->Link.port = 1935; -++ } -++ RTMP_Connect(r, NULL); -++ } -++ else -++ { -++ -++ RTMP_Log(RTMP_LOGERROR, "rtmp server requested close"); -++ if (r->m_bPlaying && (strstr(pageUrl, "streamlive.to") || strstr(pageUrl, "uk-iptv.co.uk"))) -++ RTMP_Log(RTMP_LOGINFO, "ignoring close request"); -++ else -++ RTMP_Close(r); -++ } -+ } -+ else if (AVMATCH(&method, &av_onStatus)) -+ { -+ AMFObject obj2; -+- AVal code, level; -++ AVal code, level, description; -+ AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &obj2); -+ AMFProp_GetString(AMF_GetProp(&obj2, &av_code, -1), &code); -+ AMFProp_GetString(AMF_GetProp(&obj2, &av_level, -1), &level); -++ AMFProp_GetString(AMF_GetProp(&obj2, &av_description, -1), &description); -+ -+ RTMP_Log(RTMP_LOGDEBUG, "%s, onStatus: %s", __FUNCTION__, code.av_val); -+ if (AVMATCH(&code, &av_NetStream_Failed) -+- || AVMATCH(&code, &av_NetStream_Play_Failed) -+- || AVMATCH(&code, &av_NetStream_Play_StreamNotFound) -+- || AVMATCH(&code, &av_NetConnection_Connect_InvalidApp)) -++ || AVMATCH(&code, &av_NetStream_Play_Failed) -++ || AVMATCH(&code, &av_NetStream_Play_StreamNotFound) -++ || AVMATCH(&code, &av_NetConnection_Connect_Rejected) -++ || AVMATCH(&code, &av_NetConnection_Connect_InvalidApp)) -+ { -+ r->m_stream_id = -1; -+ RTMP_Close(r); -+@@ -3171,6 +3705,46 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize) -+ r->m_pausing = 3; -+ } -+ } -++ -++ else if (AVMATCH(&code, &av_NetConnection_confStream)) -++ { -++#ifdef CRYPTO -++ static const char hexdig[] = "0123456789abcdef"; -++ AVal auth; -++ SAVC(cf_stream); -++ int i; -++ char hash_hex[33] = {0}; -++ unsigned char hash[16]; -++ -++ param_count = strsplit(description.av_val, description.av_len, ':', ¶ms); -++ if (param_count >= 3) -++ { -++ char *buf = malloc(strlen(params[0]) + r->Link.playpath.av_len + 1); -++ strcpy(buf, params[0]); -++ strncat(buf, r->Link.playpath.av_val, r->Link.playpath.av_len); -++ md5_hash((unsigned char *) buf, strlen(buf), hash); -++ for (i = 0; i < 16; i++) -++ { -++ hash_hex[i * 2] = hexdig[0x0f & (hash[i] >> 4)]; -++ hash_hex[i * 2 + 1] = hexdig[0x0f & (hash[i])]; -++ } -++ auth.av_val = &hash_hex[atoi(params[1]) - 1]; -++ auth.av_len = atoi(params[2]); -++ RTMP_Log(RTMP_LOGDEBUG, "Khalsa: %.*s", auth.av_len, auth.av_val); -++ -++ enc = pbuf; -++ enc = AMF_EncodeString(enc, pend, &av_cf_stream); -++ enc = AMF_EncodeNumber(enc, pend, txn); -++ *enc++ = AMF_NULL; -++ enc = AMF_EncodeString(enc, pend, &auth); -++ av_Command.av_val = pbuf; -++ av_Command.av_len = enc - pbuf; -++ -++ SendInvoke(r, &av_Command, FALSE); -++ free(buf); -++ } -++#endif -++ } -+ } -+ else if (AVMATCH(&method, &av_playlist_ready)) -+ { -+@@ -3184,6 +3758,109 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize) -+ } -+ } -+ } -++ else if (AVMATCH(&method, &av_cps)) -++ { -++ if (obj.o_num >= 4) -++ { -++ int Status = AMFProp_GetBoolean(AMF_GetProp(&obj, NULL, 3)); -++ if (Status == FALSE) -++ { -++ AVal Message; -++ AMFProp_GetString(AMF_GetProp(&obj, NULL, 4), &Message); -++ RTMP_Log(RTMP_LOGINFO, "Model status is %.*s", Message.av_len, Message.av_val); -++ RTMP_Close(r); -++ } -++ else -++ { -++ if (obj.o_num >= 7) -++ { -++ AVal Playpath, Server; -++ AMFProp_GetString(AMF_GetProp(&obj, NULL, 5), &Playpath); -++ AMFProp_GetString(AMF_GetProp(&obj, NULL, 6), &Server); -++ if (strncasecmp(&Playpath.av_val[Playpath.av_len - 4], ".mp4", 4) != 0) -++ { -++ char *playpath = calloc(Server.av_len + Playpath.av_len + 25, sizeof (char)); -++ strcat(playpath, "rtmp://"); -++ strncat(playpath, Server.av_val, Server.av_len); -++ strcat(playpath, "/live-origin/"); -++ strncat(playpath, Playpath.av_val, Playpath.av_len); -++ strcat(playpath, ".mp4"); -++ Playpath.av_val = playpath; -++ Playpath.av_len = strlen(playpath); -++ } -++ RTMP_ParsePlaypath(&Playpath, &r->Link.playpath); -++ RTMP_SendCreateStream(r); -++ } -++ } -++ } -++ } -++ else if (AVMATCH(&method, &av_disneyToken)) -++ { -++ double FirstNumber = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3)); -++ double SecondNumber = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 4)); -++ RTMP_Log(RTMP_LOGDEBUG, "FirstNumber: %.2f, SecondNumber: %.2f", FirstNumber, SecondNumber); -++ -++ enc = pbuf; -++ enc = AMF_EncodeString(enc, pend, &av__result); -++ enc = AMF_EncodeNumber(enc, pend, txn); -++ *enc++ = AMF_NULL; -++ enc = AMF_EncodeNumber(enc, pend, FirstNumber * SecondNumber); -++ av_Response.av_val = pbuf; -++ av_Response.av_len = enc - pbuf; -++ -++ AMF_Decode(&obj, av_Response.av_val, av_Response.av_len, FALSE); -++ AMF_Dump(&obj); -++ SendInvoke(r, &av_Response, FALSE); -++ } -++ else if (AVMATCH(&method, &av_verifyClient)) -++ { -++ double VerificationNumber = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3)); -++ RTMP_Log(RTMP_LOGDEBUG, "VerificationNumber: %.2f", VerificationNumber); -++ -++ enc = pbuf; -++ enc = AMF_EncodeString(enc, pend, &av__result); -++ enc = AMF_EncodeNumber(enc, pend, txn); -++ *enc++ = AMF_NULL; -++ enc = AMF_EncodeNumber(enc, pend, exp(atan(sqrt(VerificationNumber))) + 1); -++ av_Response.av_val = pbuf; -++ av_Response.av_len = enc - pbuf; -++ -++ AMF_Decode(&obj, av_Response.av_val, av_Response.av_len, FALSE); -++ AMF_Dump(&obj); -++ SendInvoke(r, &av_Response, FALSE); -++ } -++ else if (AVMATCH(&method, &av_sendStatus)) -++ { -++ if (r->Link.WeebToken.av_len) -++ { -++ AVal av_Authorized = AVC("User.hasAccess"); -++ AVal av_TransferLimit = AVC("User.noPremium.limited"); -++ AVal av_UserLimit = AVC("User.noPremium.tooManyUsers"); -++ AVal av_TimeLeft = AVC("timeLeft"); -++ AVal av_Status, av_ReconnectionTime; -++ -++ AMFObject Status; -++ AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &Status); -++ AMFProp_GetString(AMF_GetProp(&Status, &av_code, -1), &av_Status); -++ RTMP_Log(RTMP_LOGINFO, "%.*s", av_Status.av_len, av_Status.av_val); -++ if (AVMATCH(&av_Status, &av_Authorized)) -++ { -++ RTMP_Log(RTMP_LOGINFO, "Weeb.tv authentication successful"); -++ RTMP_SendCreateStream(r); -++ } -++ else if (AVMATCH(&av_Status, &av_UserLimit)) -++ { -++ RTMP_Log(RTMP_LOGINFO, "No free slots available"); -++ RTMP_Close(r); -++ } -++ else if (AVMATCH(&av_Status, &av_TransferLimit)) -++ { -++ AMFProp_GetString(AMF_GetProp(&Status, &av_TimeLeft, -1), &av_ReconnectionTime); -++ RTMP_Log(RTMP_LOGINFO, "Viewing limit exceeded. try again in %.*s minutes.", av_ReconnectionTime.av_len, av_ReconnectionTime.av_val); -++ RTMP_Close(r); -++ } -++ } -++ } -+ else -+ { -+ -+@@ -3209,7 +3886,8 @@ RTMP_FindFirstMatchingProperty(AMFObject *obj, const AVal *name, -+ return TRUE; -+ } -+ -+- if (prop->p_type == AMF_OBJECT || prop->p_type == AMF_ECMA_ARRAY) -++ if (prop->p_type == AMF_OBJECT || prop->p_type == AMF_ECMA_ARRAY -++ || prop->p_type == AMF_STRICT_ARRAY) -+ { -+ if (RTMP_FindFirstMatchingProperty(&prop->p_vu.p_object, name, p)) -+ return TRUE; -+@@ -3235,7 +3913,8 @@ RTMP_FindPrefixProperty(AMFObject *obj, const AVal *name, -+ return TRUE; -+ } -+ -+- if (prop->p_type == AMF_OBJECT) -++ if (prop->p_type == AMF_OBJECT || prop->p_type == AMF_ECMA_ARRAY -++ || prop->p_type == AMF_STRICT_ARRAY) -+ { -+ if (RTMP_FindPrefixProperty(&prop->p_vu.p_object, name, p)) -+ return TRUE; -+@@ -3269,6 +3948,7 @@ DumpMetaData(AMFObject *obj) -+ snprintf(str, 255, "%s", -+ prop->p_vu.p_number != 0. ? "TRUE" : "FALSE"); -+ break; -++ case AMF_NULL: -+ case AMF_STRING: -+ len = snprintf(str, 255, "%.*s", prop->p_vu.p_aval.av_len, -+ prop->p_vu.p_aval.av_val); -+@@ -3284,7 +3964,7 @@ DumpMetaData(AMFObject *obj) -+ } -+ if (str[0] && prop->p_name.av_len) -+ { -+- RTMP_Log(RTMP_LOGINFO, " %-22.*s%s", prop->p_name.av_len, -++ RTMP_Log(RTMP_LOGINFO, " %-24.*s%s", prop->p_name.av_len, -+ prop->p_name.av_val, str); -+ } -+ } -+@@ -3366,7 +4046,7 @@ HandleCtrl(RTMP *r, const RTMPPacket *packet) -+ unsigned int tmp; -+ if (packet->m_body && packet->m_nBodySize >= 2) -+ nType = AMF_DecodeInt16(packet->m_body); -+- RTMP_Log(RTMP_LOGDEBUG, "%s, received ctrl. type: %d, len: %d", __FUNCTION__, nType, -++ RTMP_Log(RTMP_LOGDEBUG, "%s, received ctrl, type: %d, len: %d", __FUNCTION__, nType, -+ packet->m_nBodySize); -+ /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */ -+ -+@@ -3475,15 +4155,15 @@ HandleCtrl(RTMP *r, const RTMPPacket *packet) -+ RTMP_Log(RTMP_LOGDEBUG, "%s, SWFVerification ping received: ", __FUNCTION__); -+ if (packet->m_nBodySize > 2 && packet->m_body[2] > 0x01) -+ { -+- RTMP_Log(RTMP_LOGERROR, -+- "%s: SWFVerification Type %d request not supported! Patches welcome...", -+- __FUNCTION__, packet->m_body[2]); -++ RTMP_Log(RTMP_LOGERROR, -++ "%s: SWFVerification Type %d request not supported, attempting to use SWFVerification Type 1! Patches welcome...", -++ __FUNCTION__, packet->m_body[2]); -+ } -+ #ifdef CRYPTO -+ /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */ -+ -+ /* respond with HMAC SHA256 of decompressed SWF, key is the 30byte player key, also the last 30 bytes of the server handshake are applied */ -+- else if (r->Link.SWFSize) -++ if (r->Link.SWFSize) -+ { -+ RTMP_SendCtrl(r, 0x1B, 0, 0); -+ } -+@@ -3788,8 +4468,18 @@ HandShake(RTMP *r, int FP9HandShake) -+ serversig[4], serversig[5], serversig[6], serversig[7]); -+ -+ /* 2nd part of handshake */ -+- if (!WriteN(r, serversig, RTMP_SIG_SIZE)) -+- return FALSE; -++ if (r->Link.CombineConnectPacket) -++ { -++ char *HandshakeResponse = malloc(RTMP_SIG_SIZE); -++ memcpy(HandshakeResponse, (char *) serversig, RTMP_SIG_SIZE); -++ r->Link.HandshakeResponse.av_val = HandshakeResponse; -++ r->Link.HandshakeResponse.av_len = RTMP_SIG_SIZE; -++ } -++ else -++ { -++ if (!WriteN(r, (char *) serversig, RTMP_SIG_SIZE)) -++ return FALSE; -++ } -+ -+ if (ReadN(r, serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE) -+ return FALSE; -+@@ -3942,7 +4632,7 @@ RTMP_SendPacket(RTMP *r, RTMPPacket *packet, int queue) -+ -+ nSize = packetSize[packet->m_headerType]; -+ hSize = nSize; cSize = 0; -+- t = packet->m_nTimeStamp - last; -++ t = packet->m_nTimeStamp ? packet->m_nTimeStamp - last : 0; -+ -+ if (packet->m_body) -+ { -+@@ -4251,8 +4941,13 @@ RTMPSockBuf_Fill(RTMPSockBuf *sb) -+ { -+ int nBytes; -+ -+- if (!sb->sb_size) -+- sb->sb_start = sb->sb_buf; -++ /* Copy unprocessed bytes to the start of buffer to make optimum use of -++ * available buffer */ -++ if (sb->sb_start != sb->sb_buf) -++ { -++ memcpy(sb->sb_buf, sb->sb_start, sb->sb_size); -++ sb->sb_start = sb->sb_buf; -++ } -+ -+ while (1) -+ { -+@@ -4266,8 +4961,10 @@ RTMPSockBuf_Fill(RTMPSockBuf *sb) -+ #endif -+ { -+ nBytes = recv(sb->sb_socket, sb->sb_start + sb->sb_size, nBytes, 0); -+- } -+- if (nBytes != -1) -++ if (!nBytes) -++ RTMP_Log(RTMP_LOGDEBUG, "Socket closed by server, nBytes: %d", nBytes); -++ } -++ if (nBytes >= 0) -+ { -+ sb->sb_size += nBytes; -+ } -+@@ -4405,21 +5102,19 @@ static int -+ HTTP_Post(RTMP *r, RTMPTCmd cmd, const char *buf, int len) -+ { -+ char hbuf[512]; -+- int hlen = snprintf(hbuf, sizeof(hbuf), "POST /%s%s/%d HTTP/1.1\r\n" -+- "Host: %.*s:%d\r\n" -+- "Accept: */*\r\n" -+- "User-Agent: Shockwave Flash\r\n" -+- "Connection: Keep-Alive\r\n" -+- "Cache-Control: no-cache\r\n" -+- "Content-type: application/x-fcs\r\n" -+- "Content-length: %d\r\n\r\n", RTMPT_cmds[cmd], -+- r->m_clientID.av_val ? r->m_clientID.av_val : "", -+- r->m_msgCounter, r->Link.hostname.av_len, r->Link.hostname.av_val, -+- r->Link.port, len); -++ int hlen = snprintf(hbuf, sizeof (hbuf), "POST /%s%s/%d HTTP/1.1\r\n" -++ "Content-Type: application/x-fcs\r\n" -++ "User-Agent: Shockwave Flash\r\n" -++ "Host: %.*s:%d\r\n" -++ "Content-Length: %d\r\n" -++ "Connection: Keep-Alive\r\n" -++ "Cache-Control: no-cache\r\n\r\n", RTMPT_cmds[cmd], -++ r->m_clientID.av_val ? r->m_clientID.av_val : "", -++ r->m_msgCounter, r->Link.hostname.av_len, r->Link.hostname.av_val, -++ r->Link.port, len); -+ RTMPSockBuf_Send(&r->m_sb, hbuf, hlen); -+ hlen = RTMPSockBuf_Send(&r->m_sb, buf, len); -+ r->m_msgCounter++; -+- r->m_unackd++; -+ return hlen; -+ } -+ -+@@ -4429,22 +5124,17 @@ HTTP_read(RTMP *r, int fill) -+ char *ptr; -+ int hlen; -+ -+-restart: -+ if (fill) -+ RTMPSockBuf_Fill(&r->m_sb); -+- if (r->m_sb.sb_size < 13) { -+- if (fill) -+- goto restart; -++ -++ /* Check if socket buffer is empty or HTTP header isn't completely received */ -++ memset(r->m_sb.sb_start + r->m_sb.sb_size, '\0', 1); -++ if ((!r->m_sb.sb_size) || (!strstr(r->m_sb.sb_start, "\r\n\r\n"))) -+ return -2; -+- } -++ -+ if (strncmp(r->m_sb.sb_start, "HTTP/1.1 200 ", 13)) -+ return -1; -+ r->m_sb.sb_start[r->m_sb.sb_size] = '\0'; -+- if (!strstr(r->m_sb.sb_start, "\r\n\r\n")) { -+- if (fill) -+- goto restart; -+- return -2; -+- } -+ -+ ptr = r->m_sb.sb_start + sizeof("HTTP/1.1 200"); -+ while ((ptr = strstr(ptr, "Content-"))) { -+@@ -4452,21 +5142,31 @@ restart: -+ ptr += 8; -+ } -+ if (!ptr) -+- return -1; -+- hlen = atoi(ptr+16); -++ { -++ ptr = r->m_sb.sb_start + sizeof ("HTTP/1.1 200"); -++ RTMP_Log(RTMP_LOGDEBUG, "No Content-Length header found, assuming continuous stream"); -++ hlen = 2147483648UL; // 2 GB -++ } -++ else -++ hlen = atoi(ptr + 16); -+ ptr = strstr(ptr+16, "\r\n\r\n"); -+ if (!ptr) -+ return -1; -+ ptr += 4; -+- if (ptr + (r->m_clientID.av_val ? 1 : hlen) > r->m_sb.sb_start + r->m_sb.sb_size) -+- { -+- if (fill) -+- goto restart; -+- return -2; -+- } -+ r->m_sb.sb_size -= ptr - r->m_sb.sb_start; -+ r->m_sb.sb_start = ptr; -+- r->m_unackd--; -++ -++ /* Stop processing if content length is 0 */ -++ if (!hlen) -++ return -3; -++ -++ /* Refill buffer if no payload is received */ -++ if (hlen && (!r->m_sb.sb_size)) -++ { -++ RTMPSockBuf_Fill(&r->m_sb); -++ ptr = r->m_sb.sb_buf; -++ r->m_sb.sb_start = ptr; -++ } -+ -+ if (!r->m_clientID.av_val) -+ { -+@@ -4486,10 +5186,17 @@ restart: -+ r->m_sb.sb_start++; -+ r->m_sb.sb_size--; -+ } -++ -++ /* Following values shouldn't be negative in any case */ -++ if (r->m_resplen < 0) -++ r->m_resplen = 0; -++ if (r->m_sb.sb_size < 0) -++ r->m_sb.sb_size = 0; -++ -+ return 0; -+ } -+ -+-#define MAX_IGNORED_FRAMES 50 -++#define MAX_IGNORED_FRAMES 100 -+ -+ /* Read from the stream until we get a media packet. -+ * Returns -3 if Play.Close/Stop, -2 if fatal error, -1 if no more media -+@@ -4557,162 +5264,156 @@ Read_1_Packet(RTMP *r, char *buf, unsigned int buflen) -+ #endif -+ -+ if (r->m_read.flags & RTMP_READ_RESUME) -+- { -+- /* check the header if we get one */ -+- if (packet.m_nTimeStamp == 0) -+- { -+- if (r->m_read.nMetaHeaderSize > 0 -+- && packet.m_packetType == RTMP_PACKET_TYPE_INFO) -+- { -+- AMFObject metaObj; -+- int nRes = -+- AMF_Decode(&metaObj, packetBody, nPacketLen, FALSE); -+- if (nRes >= 0) -+- { -+- AVal metastring; -+- AMFProp_GetString(AMF_GetProp(&metaObj, NULL, 0), -+- &metastring); -+- -+- if (AVMATCH(&metastring, &av_onMetaData)) -+- { -+- /* compare */ -+- if ((r->m_read.nMetaHeaderSize != nPacketLen) || -+- (memcmp -+- (r->m_read.metaHeader, packetBody, -+- r->m_read.nMetaHeaderSize) != 0)) -+- { -+- ret = RTMP_READ_ERROR; -+- } -+- } -+- AMF_Reset(&metaObj); -+- if (ret == RTMP_READ_ERROR) -+- break; -+- } -+- } -++ { -++ RTMP_Log(RTMP_LOGDEBUG2, "Received timestamp: %d, type %d", -++ packet.m_nTimeStamp, packet.m_packetType); -++ if (packet.m_nTimeStamp > 0 && r->m_read.nResumeDriftTS > 0) -++ packet.m_nTimeStamp -= r->m_read.nResumeDriftTS; -++ RTMP_Log(RTMP_LOGDEBUG2, "Adjusted timestamp: %d", packet.m_nTimeStamp); -++ -++ /* check the header if we get one */ -++ if (r->m_read.nMetaHeaderSize > 0 -++ && packet.m_packetType == RTMP_PACKET_TYPE_INFO) -++ { -++ AMFObject metaObj; -++ int nRes = AMF_Decode(&metaObj, packetBody, nPacketLen, FALSE); -++ if (nRes >= 0) -++ { -++ AVal metastring; -++ AMFProp_GetString(AMF_GetProp(&metaObj, NULL, 0), &metastring); -++ -++ if (AVMATCH(&metastring, &av_onMetaData)) -++ { -++ /* compare */ -++ if ((r->m_read.nMetaHeaderSize != nPacketLen) || -++ (memcmp(r->m_read.metaHeader, packetBody, r->m_read.nMetaHeaderSize) != 0)) -++ { -++ ret = RTMP_READ_ERROR; -++ } -++ } -++ AMF_Reset(&metaObj); -++ if (ret == RTMP_READ_ERROR) -++ break; -++ } -++ } -+ -+- /* check first keyframe to make sure we got the right position -+- * in the stream! (the first non ignored frame) -+- */ -+- if (r->m_read.nInitialFrameSize > 0) -+- { -+- /* video or audio data */ -+- if (packet.m_packetType == r->m_read.initialFrameType -+- && r->m_read.nInitialFrameSize == nPacketLen) -+- { -+- /* we don't compare the sizes since the packet can -+- * contain several FLV packets, just make sure the -+- * first frame is our keyframe (which we are going -+- * to rewrite) -+- */ -+- if (memcmp -+- (r->m_read.initialFrame, packetBody, -+- r->m_read.nInitialFrameSize) == 0) -+- { -+- RTMP_Log(RTMP_LOGDEBUG, "Checked keyframe successfully!"); -+- r->m_read.flags |= RTMP_READ_GOTKF; -+- /* ignore it! (what about audio data after it? it is -+- * handled by ignoring all 0ms frames, see below) -+- */ -+- ret = RTMP_READ_IGNORE; -+- break; -+- } -+- } -++ /* check first keyframe to make sure we got the right position -++ * in the stream! (the first non ignored frame) -++ */ -++ RTMP_Log(RTMP_LOGDEBUG2, "Required packet length: %d, Packet length: %d", -++ r->m_read.nInitialFrameSize, nPacketLen); -++ if (r->m_read.nInitialFrameSize > 0) -++ { -++ /* video or audio data */ -++ if (packet.m_packetType == r->m_read.initialFrameType -++ && r->m_read.nInitialFrameSize == nPacketLen) -++ { -++ /* we don't compare the sizes since the packet can -++ * contain several FLV packets, just make sure the -++ * first frame is our keyframe (which we are going -++ * to rewrite) -++ */ -++ RTMP_Log(RTMP_LOGDEBUG2, "Comparing keyframe data"); -++ if (memcmp(r->m_read.initialFrame, packetBody, -++ r->m_read.nInitialFrameSize) == 0) -++ { -++ RTMP_Log(RTMP_LOGDEBUG, "Checked keyframe successfully!"); -++ r->m_read.flags |= RTMP_READ_GOTKF; -++ r->m_read.nResumeDriftTS = packet.m_nTimeStamp; -++ /* ignore it! (what about audio data after it? it is -++ * handled by ignoring all 0ms frames, see below) -++ */ -++ ret = RTMP_READ_IGNORE; -++ break; -++ } -++ } -+ -+- /* hande FLV streams, even though the server resends the -+- * keyframe as an extra video packet it is also included -+- * in the first FLV stream chunk and we have to compare -+- * it and filter it out !! -+- */ -+- if (packet.m_packetType == RTMP_PACKET_TYPE_FLASH_VIDEO) -+- { -+- /* basically we have to find the keyframe with the -+- * correct TS being nResumeTS -+- */ -+- unsigned int pos = 0; -+- uint32_t ts = 0; -+- -+- while (pos + 11 < nPacketLen) -+- { -+- /* size without header (11) and prevTagSize (4) */ -+- uint32_t dataSize = -+- AMF_DecodeInt24(packetBody + pos + 1); -+- ts = AMF_DecodeInt24(packetBody + pos + 4); -+- ts |= (packetBody[pos + 7] << 24); -++ /* hande FLV streams, even though the server resends the -++ * keyframe as an extra video packet it is also included -++ * in the first FLV stream chunk and we have to compare -++ * it and filter it out !! -++ */ -++ if (packet.m_packetType == RTMP_PACKET_TYPE_FLASH_VIDEO) -++ { -++ /* basically we have to find the keyframe with the -++ * correct TS being nResumeTS -++ */ -++ unsigned int pos = 0; -++ uint32_t ts = 0; -++ -++ while (pos + 11 < nPacketLen) -++ { -++ /* size without header (11) and prevTagSize (4) */ -++ uint32_t dataSize = AMF_DecodeInt24(packetBody + pos + 1); -++ ts = AMF_DecodeInt24(packetBody + pos + 4); -++ ts |= (packetBody[pos + 7] << 24); -+ -+ #ifdef _DEBUG -+- RTMP_Log(RTMP_LOGDEBUG, -+- "keyframe search: FLV Packet: type %02X, dataSize: %d, timeStamp: %d ms", -+- packetBody[pos], dataSize, ts); -++ RTMP_Log(RTMP_LOGDEBUG, -++ "keyframe search: FLV Packet: type %02X, dataSize: %d, timeStamp: %d ms", -++ packetBody[pos], dataSize, ts); -+ #endif -+- /* ok, is it a keyframe?: -+- * well doesn't work for audio! -+- */ -+- if (packetBody[pos /*6928, test 0 */ ] == -+- r->m_read.initialFrameType -+- /* && (packetBody[11]&0xf0) == 0x10 */ ) -+- { -+- if (ts == r->m_read.nResumeTS) -+- { -+- RTMP_Log(RTMP_LOGDEBUG, -+- "Found keyframe with resume-keyframe timestamp!"); -+- if (r->m_read.nInitialFrameSize != dataSize -+- || memcmp(r->m_read.initialFrame, -+- packetBody + pos + 11, -+- r->m_read. -+- nInitialFrameSize) != 0) -+- { -+- RTMP_Log(RTMP_LOGERROR, -+- "FLV Stream: Keyframe doesn't match!"); -+- ret = RTMP_READ_ERROR; -+- break; -+- } -+- r->m_read.flags |= RTMP_READ_GOTFLVK; -+- -+- /* skip this packet? -+- * check whether skippable: -+- */ -+- if (pos + 11 + dataSize + 4 > nPacketLen) -+- { -+- RTMP_Log(RTMP_LOGWARNING, -+- "Non skipable packet since it doesn't end with chunk, stream corrupt!"); -+- ret = RTMP_READ_ERROR; -+- break; -+- } -+- packetBody += (pos + 11 + dataSize + 4); -+- nPacketLen -= (pos + 11 + dataSize + 4); -+- -+- goto stopKeyframeSearch; -+- -+- } -+- else if (r->m_read.nResumeTS < ts) -+- { -+- /* the timestamp ts will only increase with -+- * further packets, wait for seek -+- */ -+- goto stopKeyframeSearch; -+- } -+- } -+- pos += (11 + dataSize + 4); -+- } -+- if (ts < r->m_read.nResumeTS) -+- { -+- RTMP_Log(RTMP_LOGERROR, -+- "First packet does not contain keyframe, all " -+- "timestamps are smaller than the keyframe " -+- "timestamp; probably the resume seek failed?"); -+- } -+- stopKeyframeSearch: -+- ; -+- if (!(r->m_read.flags & RTMP_READ_GOTFLVK)) -+- { -+- RTMP_Log(RTMP_LOGERROR, -+- "Couldn't find the seeked keyframe in this chunk!"); -+- ret = RTMP_READ_IGNORE; -+- break; -+- } -+- } -+- } -+- } -++ /* ok, is it a keyframe?: -++ * well doesn't work for audio! -++ */ -++ if (packetBody[pos /*6928, test 0 */ ] == r->m_read.initialFrameType -++ /* && (packetBody[11]&0xf0) == 0x10 */) -++ { -++ if (ts == r->m_read.nResumeTS) -++ { -++ RTMP_Log(RTMP_LOGDEBUG, "Found keyframe with resume-keyframe timestamp!"); -++ if (r->m_read.nInitialFrameSize != dataSize || -++ memcmp(r->m_read.initialFrame, packetBody + pos + 11, -++ r->m_read.nInitialFrameSize) != 0) -++ { -++ RTMP_Log(RTMP_LOGERROR, "FLV Stream: Keyframe doesn't match!"); -++ ret = RTMP_READ_ERROR; -++ break; -++ } -++ r->m_read.flags |= RTMP_READ_GOTFLVK; -++ -++ /* skip this packet? -++ * check whether skippable: -++ */ -++ if (pos + 11 + dataSize + 4 > nPacketLen) -++ { -++ RTMP_Log(RTMP_LOGWARNING, "Non skipable packet since it doesn't " -++ "end with chunk, stream corrupt!"); -++ ret = RTMP_READ_ERROR; -++ break; -++ } -++ packetBody += (pos + 11 + dataSize + 4); -++ nPacketLen -= (pos + 11 + dataSize + 4); -++ -++ goto stopKeyframeSearch; -++ -++ } -++ else if (r->m_read.nResumeTS < ts) -++ { -++ /* the timestamp ts will only increase with -++ * further packets, wait for seek -++ */ -++ goto stopKeyframeSearch; -++ } -++ } -++ pos += (11 + dataSize + 4); -++ } -++ if (ts < r->m_read.nResumeTS) -++ { -++ RTMP_Log(RTMP_LOGERROR, -++ "First packet does not contain keyframe, all " -++ "timestamps are smaller than the keyframe " -++ "timestamp; probably the resume seek failed?"); -++ } -++ stopKeyframeSearch: -++ if (!(r->m_read.flags & RTMP_READ_GOTFLVK)) -++ { -++ RTMP_Log(RTMP_LOGERROR, "Couldn't find the seeked keyframe in this chunk!"); -++ ret = RTMP_READ_IGNORE; -++ break; -++ } -++ } -++ } -+ -+ if (packet.m_nTimeStamp > 0 -+ && (r->m_read.flags & (RTMP_READ_GOTKF|RTMP_READ_GOTFLVK))) -+@@ -4972,7 +5673,7 @@ static const char flvHeader[] = { 'F', 'L', 'V', 0x01, -+ 0x00, 0x00, 0x00, 0x00 -+ }; -+ -+-#define HEADERBUF (128*1024) -++#define HEADERBUF (1024*1024) -+ int -+ RTMP_Read(RTMP *r, char *buf, int size) -+ { -+@@ -5175,3 +5876,395 @@ RTMP_Write(RTMP *r, const char *buf, int size) -+ } -+ return size+s2; -+ } -++ -++AVal -++AVcopy(AVal src) -++{ -++ AVal dst; -++ if (src.av_len) -++ { -++ dst.av_val = malloc(src.av_len + 1); -++ memcpy(dst.av_val, src.av_val, src.av_len); -++ dst.av_val[src.av_len] = '\0'; -++ dst.av_len = src.av_len; -++ } -++ else -++ { -++ dst.av_val = NULL; -++ dst.av_len = 0; -++ } -++ return dst; -++} -++ -++static int -++ConnectSocket(RTMP *r) -++{ -++ int on = 1; -++ struct sockaddr_in service; -++ if (!r->Link.hostname.av_len) -++ return FALSE; -++ -++ memset(&service, 0, sizeof (struct sockaddr_in)); -++ service.sin_family = AF_INET; -++ -++ if (r->Link.socksport) -++ { -++ /* Connect via SOCKS */ -++ if (!add_addr_info(&service, &r->Link.sockshost, r->Link.socksport)) -++ return FALSE; -++ } -++ else -++ { -++ /* Connect directly */ -++ if (!add_addr_info(&service, &r->Link.hostname, r->Link.port)) -++ return FALSE; -++ } -++ -++ r->m_sb.sb_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); -++ if (r->m_sb.sb_socket != -1) -++ { -++ if (connect(r->m_sb.sb_socket, (struct sockaddr *) &service, sizeof (struct sockaddr)) < 0) -++ { -++ int err = GetSockError(); -++ RTMP_Log(RTMP_LOGERROR, "%s, failed to connect socket. %d (%s)", -++ __FUNCTION__, err, strerror(err)); -++ RTMP_Close(r); -++ return FALSE; -++ } -++ -++ if (r->Link.socksport) -++ { -++ RTMP_Log(RTMP_LOGDEBUG, "%s ... SOCKS negotiation", __FUNCTION__); -++ if (!SocksNegotiate(r)) -++ { -++ RTMP_Log(RTMP_LOGERROR, "%s, SOCKS negotiation failed.", __FUNCTION__); -++ RTMP_Close(r); -++ return FALSE; -++ } -++ } -++ } -++ else -++ { -++ RTMP_Log(RTMP_LOGERROR, "%s, failed to create socket. Error: %d", -++ __FUNCTION__, GetSockError()); -++ return FALSE; -++ } -++ -++ /* set timeout */ -++ SET_RCVTIMEO(tv, r->Link.timeout); -++ if (setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, sizeof (tv))) -++ { -++ RTMP_Log(RTMP_LOGERROR, "%s, Setting socket timeout to %d failed!", -++ __FUNCTION__, r->Link.timeout); -++ } -++ -++ setsockopt(r->m_sb.sb_socket, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof (on)); -++ if (r->Link.protocol & RTMP_FEATURE_HTTP) -++ setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof (on)); -++ -++ return TRUE; -++} -++ -++static int -++SendCommand(RTMP *r, char *method, int queue) -++{ -++ char pbuf[256], *pend = pbuf + sizeof (pbuf), *enc; -++ AVal av_command, methodName; -++ -++ enc = pbuf; -++ methodName.av_val = method; -++ methodName.av_len = strlen(method); -++ enc = AMF_EncodeString(enc, pend, &methodName); -++ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -++ *enc++ = AMF_NULL; -++ av_command.av_val = pbuf; -++ av_command.av_len = enc - pbuf; -++ -++ return SendInvoke(r, &av_command, queue); -++} -++ -++static int -++SendGetStreamLength(RTMP *r) -++{ -++ char pbuf[256], *pend = pbuf + sizeof (pbuf), *enc; -++ AVal av_Command; -++ SAVC(getStreamLength); -++ -++ enc = pbuf; -++ enc = AMF_EncodeString(enc, pend, &av_getStreamLength); -++ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -++ *enc++ = AMF_NULL; -++ enc = AMF_EncodeString(enc, pend, &r->Link.playpath); -++ av_Command.av_val = pbuf; -++ av_Command.av_len = enc - pbuf; -++ -++ return SendInvoke(r, &av_Command, TRUE); -++} -++ -++static int -++SendInvoke(RTMP *r, AVal *command, int queue) -++{ -++ RTMPPacket packet; -++ char pbuf[512], *enc; -++ -++ packet.m_nChannel = 0x03; /* control channel (invoke) */ -++ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM; -++ packet.m_packetType = RTMP_PACKET_TYPE_INVOKE; -++ packet.m_nTimeStamp = 0; -++ packet.m_nInfoField2 = 0; -++ packet.m_hasAbsTimestamp = 0; -++ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE; -++ -++ enc = packet.m_body; -++ if (command->av_len) -++ { -++ memcpy(enc, command->av_val, command->av_len); -++ enc += command->av_len; -++ } -++ else -++ return FALSE; -++ packet.m_nBodySize = enc - packet.m_body; -++ -++ return RTMP_SendPacket(r, &packet, queue); -++} -++ -++AVal -++StripParams(AVal *src) -++{ -++ AVal str; -++ if (src->av_val) -++ { -++ str.av_val = calloc(src->av_len + 1, sizeof (char)); -++ strncpy(str.av_val, src->av_val, src->av_len); -++ str.av_len = src->av_len; -++ char *start = str.av_val; -++ char *end = start + str.av_len; -++ char *ptr = start; -++ -++ while (ptr < end) -++ { -++ if (*ptr == '?') -++ { -++ str.av_len = ptr - start; -++ break; -++ } -++ ptr++; -++ } -++ memset(start + str.av_len, 0, 1); -++ -++ char *dynamic = strstr(start, "[[DYNAMIC]]"); -++ if (dynamic) -++ { -++ dynamic -= 1; -++ memset(dynamic, 0, 1); -++ str.av_len = dynamic - start; -++ end = start + str.av_len; -++ } -++ -++ char *import = strstr(start, "[[IMPORT]]"); -++ if (import) -++ { -++ str.av_val = import + 11; -++ strcpy(start, "http://"); -++ str.av_val = strcat(start, str.av_val); -++ str.av_len = strlen(str.av_val); -++ } -++ return str; -++ } -++ str = *src; -++ return str; -++} -++ -++char * -++strreplace(char *srcstr, int srclen, char *orig, char *repl, int didAlloc) -++{ -++ char *ptr = NULL, *sptr = srcstr; -++ int origlen = strlen(orig); -++ int repllen = strlen(repl); -++ if (!srclen) -++ srclen = strlen(srcstr); -++ char *srcend = srcstr + srclen; -++ int dstbuffer = srclen / origlen * repllen; -++ if (dstbuffer < srclen) -++ dstbuffer = srclen; -++ char *dststr = calloc(dstbuffer + 1, sizeof (char)); -++ char *dptr = dststr; -++ -++ if ((ptr = strstr(srcstr, orig))) -++ { -++ while (ptr < srcend && (ptr = strstr(sptr, orig))) -++ { -++ int len = ptr - sptr; -++ memcpy(dptr, sptr, len); -++ sptr += len + origlen; -++ dptr += len; -++ memcpy(dptr, repl, repllen); -++ dptr += repllen; -++ } -++ memcpy(dptr, sptr, srcend - sptr); -++ if (didAlloc) -++ free(srcstr); -++ return dststr; -++ } -++ -++ memcpy(dststr, srcstr, srclen); -++ if (didAlloc) -++ free(srcstr); -++ return dststr; -++} -++ -++int -++strsplit(char *src, int srclen, char delim, char ***params) -++{ -++ char *sptr, *srcbeg, *srcend, *dstr; -++ int count = 1, i = 0, len = 0; -++ -++ if (src == NULL) -++ return 0; -++ if (!srclen) -++ srclen = strlen(src); -++ srcbeg = src; -++ srcend = srcbeg + srclen; -++ sptr = srcbeg; -++ -++ /* count the delimiters */ -++ while (sptr < srcend) -++ { -++ if (*sptr++ == delim) -++ count++; -++ } -++ sptr = srcbeg; -++ *params = malloc(count * sizeof (size_t)); -++ char **param = *params; -++ -++ for (i = 0; i < (count - 1); i++) -++ { -++ dstr = strchr(sptr, delim); -++ len = dstr - sptr; -++ param[i] = malloc((len + 1) * sizeof (char)); -++ memcpy(param[i], sptr, len); -++ *(param[i] + len) = '\0'; -++ sptr += len + 1; -++ } -++ -++ /* copy the last string */ -++ if (sptr <= srcend) -++ { -++ len = srclen - (sptr - srcbeg); -++ param[i] = malloc((len + 1) * sizeof (char)); -++ memcpy(param[i], sptr, len); -++ *(param[i] + len) = '\0'; -++ } -++ return count; -++} -++ -++void -++TransformRot13(AMFObject *obj, AVal *rindex, AVal *r) -++{ -++ char *chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMabcdefghijklmnopqrstuvwxyzabcdefghijklm"; -++ int i = 0, pos = 0; -++ AMFObject obj2; -++ -++ AMFProp_GetObject(AMF_GetProp(obj, NULL, 3), &obj2); -++ AMFProp_GetString(AMF_GetProp(&obj2, rindex, -1), r); -++ -++ for (i = 0; i < r->av_len; i++) -++ { -++ char *chr = &r->av_val[i]; -++ chr = strchr(chars, *chr); -++ pos = chr ? chr - chars : -1; -++ if (pos > -1) -++ r->av_val[i] = chars[pos + 13]; -++ } -++} -++ -++void -++__TeaCrypt(uint32_t *block, uint32_t len, uint32_t *key) -++{ -++ uint32_t z = block[len - 1], y = block[0], sum = 0, e, DELTA = 0x9e3779b9; -++ int32_t p, q; -++ -++ q = 6 + 52 / len; -++ while (q-- > 0) -++ { -++ sum += DELTA; -++ e = (sum >> 2) & 3; -++ for (p = 0; p < len - 1; p++) -++ { -++ y = block[p + 1]; -++ block[p] += ((z >> 5^y << 2) + (y >> 3^z << 4)) ^ ((sum^y) + (key[(p & 3)^e] ^ z)); -++ z = block[p]; -++ } -++ y = block[0]; -++ block[len - 1] += ((z >> 5^y << 2) + (y >> 3^z << 4)) ^ ((sum^y) + (key[(p & 3)^e] ^ z)); -++ z = block[len - 1]; -++ } -++} -++ -++AVal -++TeaEncrypt(AVal *srcData, AVal *srcKey) -++{ -++ int i, reqPadding, longKeyBlocks, longDataBlocks; -++ unsigned char *key, *data; -++ -++ // Prepare key -++ int srcKeyLen = srcKey->av_len; -++ int reqKeyLen = 16; -++ reqPadding = reqKeyLen - srcKeyLen; -++ if (reqPadding < 0) -++ { -++ reqPadding = 0; -++ srcKeyLen = reqKeyLen; -++ } -++ key = calloc((srcKeyLen + reqPadding + 1), sizeof (char)); -++ memcpy(key, srcKey->av_val, srcKeyLen); -++ longKeyBlocks = reqKeyLen / 4; -++ uint32_t *longKeyBuf = (uint32_t *) malloc(longKeyBlocks * sizeof (uint32_t)); -++ for (i = 0; i < longKeyBlocks; i++) -++ { -++ longKeyBuf[i] = 0; -++ longKeyBuf[i] |= (key[i * 4 + 0]) | (key[i * 4 + 1] << 8) | (key[i * 4 + 2] << 16) | (key[i * 4 + 3] << 24); -++ } -++ -++ // Prepare data -++ int srcDataLen = srcData->av_len; -++ reqPadding = ((int) ((srcDataLen + 3) / 4))*4 - srcDataLen; -++ if ((srcDataLen + reqPadding) < 8) -++ reqPadding = 8 - srcDataLen; -++ data = calloc((srcDataLen + reqPadding + 1), sizeof (char)); -++ memcpy(data, srcData->av_val, srcDataLen); -++ longDataBlocks = (srcDataLen + reqPadding) / 4; -++ uint32_t *longDataBuf = malloc(longDataBlocks * sizeof (uint32_t)); -++ for (i = 0; i < longDataBlocks; i++) -++ { -++ longDataBuf[i] = 0; -++ longDataBuf[i] |= (data[i * 4 + 0]) | (data[i * 4 + 1] << 8) | (data[i * 4 + 2] << 16) | (data[i * 4 + 3] << 24); -++ } -++ -++ // Encrypt data -++ __TeaCrypt(longDataBuf, longDataBlocks, longKeyBuf); -++ -++ // Convert data back to char array -++ for (i = 0; i < longDataBlocks; i++) -++ { -++ data[i * 4 + 0] = longDataBuf[i] & 0xFF; -++ data[i * 4 + 1] = (longDataBuf[i] >> 8) & 0xFF; -++ data[i * 4 + 2] = (longDataBuf[i] >> 16) & 0xFF; -++ data[i * 4 + 3] = (longDataBuf[i] >> 24) & 0xFF; -++ } -++ -++ // Convert to hex string -++ AVal hexData; -++ hexData.av_val = calloc((longDataBlocks * 4 * 2) + 1, sizeof (char)); -++ for (i = 0; i < (longDataBlocks * 4); i++) -++ sprintf(&hexData.av_val[i * 2], "%.2X", data[i]); -++ hexData.av_len = strlen(hexData.av_val); -++ -++ // Free allocated resources -++ free(key); -++ free(longKeyBuf); -++ free(data); -++ free(longDataBuf); -++ -++ return hexData; -++} -+diff --git librtmp/rtmp.h librtmp/rtmp.h -+index 0248913..3e573da 100644 -+--- librtmp/rtmp.h -++++ librtmp/rtmp.h -+@@ -150,12 +150,15 @@ extern "C" -+ AVal playpath; /* passed in explicitly */ -+ AVal tcUrl; -+ AVal swfUrl; -++ AVal swfHash; -+ AVal pageUrl; -+ AVal app; -+ AVal auth; -+ AVal flashVer; -+ AVal subscribepath; -++ AVal ccomm; -+ AVal usherToken; -++ AVal WeebToken; -+ AVal token; -+ AVal pubUser; -+ AVal pubPasswd; -+@@ -175,9 +178,18 @@ extern "C" -+ int lFlags; -+ -+ int swfAge; -++ int swfSize; -+ -+ int protocol; -++ int ConnectPacket; -++ int CombineConnectPacket; -++ int redirected; -+ int timeout; /* connection timeout in seconds */ -++ int dynamicPublish; -++ AVal dynamicCommand; -++ AVal Extras; -++ AVal HandshakeResponse; -++ double publishId; -+ -+ int pFlags; /* unused, but kept to avoid breaking ABI */ -+ -+@@ -220,6 +232,7 @@ extern "C" -+ /* if bResume == TRUE */ -+ uint8_t initialFrameType; -+ uint32_t nResumeTS; -++ uint32_t nResumeDriftTS; -+ char *metaHeader; -+ char *initialFrame; -+ uint32_t nMetaHeaderSize; -+@@ -306,6 +319,8 @@ extern "C" -+ AVal *flashVer, -+ AVal *subscribepath, -+ AVal *usherToken, -++ AVal *WeebToken, -++ AVal *ccomm, -+ int dStart, -+ int dStop, int bLiveStream, long int timeout); -+ -+@@ -371,6 +386,11 @@ extern "C" -+ int RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash, -+ int age); -+ -++ AVal AVcopy(AVal src); -++ AVal StripParams(AVal *src); -++ char *strreplace(char *srcstr, int srclen, char *orig, char *repl, int didAlloc); -++ int strsplit(char *src, int srclen, char delim, char ***params); -++ -+ #ifdef __cplusplus -+ }; -+ #endif -+diff --git librtmp/rtmp_sys.h librtmp/rtmp_sys.h -+index 85d7e53..b2a3438 100644 -+--- librtmp/rtmp_sys.h -++++ librtmp/rtmp_sys.h -+@@ -65,6 +65,7 @@ -+ #include -+ #include -+ #include -++#include -+ #if POLARSSL_VERSION_NUMBER < 0x01010000 -+ #define havege_random havege_rand -+ #endif -+@@ -105,6 +106,7 @@ typedef struct tls_server_ctx { -+ #define TLS_write(s,b,l) ssl_write(s,(unsigned char *)b,l) -+ #define TLS_shutdown(s) ssl_close_notify(s) -+ #define TLS_close(s) ssl_free(s); free(s) -++#define md5_hash(i, ilen, o) md5(i, ilen, o) -+ -+ #elif defined(USE_GNUTLS) -+ #include -+@@ -122,6 +124,8 @@ typedef struct tls_ctx { -+ #define TLS_write(s,b,l) gnutls_record_send(s,b,l) -+ #define TLS_shutdown(s) gnutls_bye(s, GNUTLS_SHUT_RDWR) -+ #define TLS_close(s) gnutls_deinit(s) -++#define md5_hash(i, ilen, o) gnutls_digest_algorithm_t algorithm = GNUTLS_DIG_MD5;\ -++ gnutls_hash_fast(algorithm, i, ilen, o); -+ -+ #else /* USE_OPENSSL */ -+ #define TLS_CTX SSL_CTX * -+@@ -134,6 +138,7 @@ typedef struct tls_ctx { -+ #define TLS_write(s,b,l) SSL_write(s,b,l) -+ #define TLS_shutdown(s) SSL_shutdown(s) -+ #define TLS_close(s) SSL_free(s) -++#define md5_hash(i, ilen, o) MD5(i, ilen, o) -+ -+ #endif -+ #endif -+diff --git rtmpdump.c rtmpdump.c -+index 13741a7..b3ae33f 100644 -+--- rtmpdump.c -++++ rtmpdump.c -+@@ -36,6 +36,9 @@ -+ #ifdef WIN32 -+ #define fseeko fseeko64 -+ #define ftello ftello64 -++#ifdef __MINGW32__ -++#define off_t off64_t -++#endif -+ #include -+ #include -+ #define SET_BINMODE(f) setmode(fileno(f), O_BINARY) -+@@ -67,7 +70,7 @@ InitSockets() -+ #endif -+ } -+ -+-inline void -++static inline void -+ CleanupSockets() -+ { -+ #ifdef WIN32 -+@@ -148,9 +151,9 @@ OpenResumeFile(const char *flvFile, // file name [in] -+ if (!*file) -+ return RD_SUCCESS; // RD_SUCCESS, because we go to fresh file mode instead of quiting -+ -+- fseek(*file, 0, SEEK_END); -++ fseeko(*file, 0, SEEK_END); -+ *size = ftello(*file); -+- fseek(*file, 0, SEEK_SET); -++ fseeko(*file, 0, SEEK_SET); -+ -+ if (*size > 0) -+ { -+@@ -178,7 +181,7 @@ OpenResumeFile(const char *flvFile, // file name [in] -+ } -+ -+ uint32_t dataOffset = AMF_DecodeInt32(hbuf + 5); -+- fseek(*file, dataOffset, SEEK_SET); -++ fseeko(*file, dataOffset, SEEK_SET); -+ -+ if (fread(hbuf, 1, 4, *file) != 4) -+ { -+@@ -283,18 +286,24 @@ GetLastKeyframe(FILE * file, // output file [in] -+ uint8_t dataType; -+ int bAudioOnly; -+ off_t size; -++ char *syncbuf, *p; -+ -+- fseek(file, 0, SEEK_END); -++ fseeko(file, 0, SEEK_END); -+ size = ftello(file); -++ if (size <= 0) -++ { -++ dSeek = 0; -++ return RD_SUCCESS; -++ } -+ -+- fseek(file, 4, SEEK_SET); -++ fseeko(file, 4, SEEK_SET); -+ if (fread(&dataType, sizeof(uint8_t), 1, file) != 1) -+ return RD_FAILED; -+ -+ bAudioOnly = (dataType & 0x4) && !(dataType & 0x1); -+ -+- RTMP_Log(RTMP_LOGDEBUG, "bAudioOnly: %d, size: %llu", bAudioOnly, -+- (unsigned long long) size); -++ RTMP_Log(RTMP_LOGDEBUG, "bAudioOnly: %d, size: %lu", bAudioOnly, -++ (unsigned long) size); -+ -+ // ok, we have to get the timestamp of the last keyframe (only keyframes are seekable) / last audio frame (audio only streams) -+ -+@@ -326,6 +335,51 @@ GetLastKeyframe(FILE * file, // output file [in] -+ prevTagSize = AMF_DecodeInt32(buffer); -+ //RTMP_Log(RTMP_LOGDEBUG, "Last packet: prevTagSize: %d", prevTagSize); -+ -++ if (prevTagSize <= 0 || prevTagSize > size - 4 - 13) -++ { -++ /* Last packet was not fully received - try to sync to last tag */ -++ prevTagSize = 0; -++ tsize = size > 0x100000 ? 0x100000 : size; /* 1MB should be enough for 3500K bitrates */ -++ if (tsize > 13 + 15) -++ { -++ tsize -= 13; // do not read header -++ syncbuf = (char *) malloc(tsize); -++ if (syncbuf) -++ { -++ fseeko(file, size - tsize, SEEK_SET); -++ if (fread(syncbuf, 1, tsize, file) == tsize) -++ { -++ p = syncbuf + tsize; -++ while (p >= syncbuf + 15) -++ { -++ /* Check for StreamID */ -++ if (AMF_DecodeInt24(p - 7) == 0) -++ { -++ /* Check for Audio/Video/Script */ -++ dataType = p[-15] & 0x1F; -++ if (dataType == 8 || dataType == 9 || dataType == 18) -++ { -++ prevTagSize = AMF_DecodeInt24(p - 14); -++ if ((prevTagSize < tsize) && (p + prevTagSize + 11 <= syncbuf + tsize - 4) -++ && (AMF_DecodeInt32(p - 4 + prevTagSize) == prevTagSize + 11)) -++ { -++ prevTagSize = syncbuf + tsize - p + 15; -++ RTMP_Log(RTMP_LOGDEBUG, "Sync success - found last tag at 0x%x", (uint32_t) (size - prevTagSize)); -++ prevTagSize -= 4; -++ tsize = 0; -++ break; -++ } -++ else -++ prevTagSize = 0; -++ } -++ } -++ --p; -++ } -++ } -++ free(syncbuf); -++ } -++ } -++ } -+ if (prevTagSize == 0) -+ { -+ RTMP_Log(RTMP_LOGERROR, "Couldn't find keyframe to resume from!"); -+@@ -703,8 +757,12 @@ void usage(char *prog) -+ RTMP_LogPrintf -+ ("--token|-T key Key for SecureToken response\n"); -+ RTMP_LogPrintf -++ ("--ccommand|-K key Send custom command before play\n"); -++ RTMP_LogPrintf -+ ("--jtv|-j JSON Authentication token for Justin.tv legacy servers\n"); -+ RTMP_LogPrintf -++ ("--weeb|-J string Authentication token for weeb.tv servers\n"); -++ RTMP_LogPrintf -+ ("--hashes|-# Display progress with hashes, not with the byte counter\n"); -+ RTMP_LogPrintf -+ ("--buffer|-b Buffer time in milliseconds (default: %u)\n", -+@@ -751,7 +809,9 @@ main(int argc, char **argv) -+ AVal hostname = { 0, 0 }; -+ AVal playpath = { 0, 0 }; -+ AVal subscribepath = { 0, 0 }; -+- AVal usherToken = { 0, 0 }; //Justin.tv auth token -++ AVal usherToken = { 0, 0 }; // Justin.tv auth token -++ AVal WeebToken = { 0, 0 }; // Weeb.tv auth token -++ AVal ccomm = { 0, 0 }; -+ int port = -1; -+ int protocol = RTMP_PROTOCOL_UNDEFINED; -+ int retries = 0; -+@@ -853,17 +913,19 @@ main(int argc, char **argv) -+ {"start", 1, NULL, 'A'}, -+ {"stop", 1, NULL, 'B'}, -+ {"token", 1, NULL, 'T'}, -++ {"ccommand", 1, NULL, 'K'}, -+ {"hashes", 0, NULL, '#'}, -+ {"debug", 0, NULL, 'z'}, -+ {"quiet", 0, NULL, 'q'}, -+ {"verbose", 0, NULL, 'V'}, -+ {"jtv", 1, NULL, 'j'}, -++ {"weeb", 1, NULL, 'J'}, -+ {0, 0, 0, 0} -+ }; -+ -+ while ((opt = -+ getopt_long(argc, argv, -+- "hVveqzRr:s:t:i:p:a:b:f:o:u:C:n:c:l:y:Ym:k:d:A:B:T:w:x:W:X:S:#j:", -++ "hVveqzRr:s:t:i:p:a:b:f:o:u:C:n:c:l:y:Ym:k:d:A:B:T:K:w:x:W:X:S:#j:J:", -+ longopts, NULL)) != -1) -+ { -+ switch (opt) -+@@ -995,7 +1057,7 @@ main(int argc, char **argv) -+ port = parsedPort; -+ if (playpath.av_len == 0 && parsedPlaypath.av_len) -+ { -+- playpath = parsedPlaypath; -++ playpath = AVcopy(parsedPlaypath); -+ } -+ if (protocol == RTMP_PROTOCOL_UNDEFINED) -+ protocol = parsedProtocol; -+@@ -1061,6 +1123,9 @@ main(int argc, char **argv) -+ RTMP_SetOpt(&rtmp, &av_token, &token); -+ } -+ break; -++ case 'K': -++ STR2AVAL(ccomm, optarg); -++ break; -+ case '#': -+ bHashes = TRUE; -+ break; -+@@ -1079,6 +1144,9 @@ main(int argc, char **argv) -+ case 'j': -+ STR2AVAL(usherToken, optarg); -+ break; -++ case 'J': -++ STR2AVAL(WeebToken, optarg); -++ break; -+ default: -+ RTMP_LogPrintf("unknown option: %c\n", opt); -+ usage(argv[0]); -+@@ -1170,14 +1238,14 @@ main(int argc, char **argv) -+ -+ if (tcUrl.av_len == 0) -+ { -+- tcUrl.av_len = strlen(RTMPProtocolStringsLower[protocol]) + -+- hostname.av_len + app.av_len + sizeof("://:65535/"); -++ tcUrl.av_len = strlen(RTMPProtocolStringsLower[protocol]) + -++ hostname.av_len + app.av_len + sizeof ("://:65535/"); -+ tcUrl.av_val = (char *) malloc(tcUrl.av_len); -+- if (!tcUrl.av_val) -+- return RD_FAILED; -++ if (!tcUrl.av_val) -++ return RD_FAILED; -+ tcUrl.av_len = snprintf(tcUrl.av_val, tcUrl.av_len, "%s://%.*s:%d/%.*s", -+- RTMPProtocolStringsLower[protocol], hostname.av_len, -+- hostname.av_val, port, app.av_len, app.av_val); -++ RTMPProtocolStringsLower[protocol], hostname.av_len, -++ hostname.av_val, port, app.av_len, app.av_val); -+ } -+ -+ int first = 1; -+@@ -1197,8 +1265,9 @@ main(int argc, char **argv) -+ if (!fullUrl.av_len) -+ { -+ RTMP_SetupStream(&rtmp, protocol, &hostname, port, &sockshost, &playpath, -+- &tcUrl, &swfUrl, &pageUrl, &app, &auth, &swfHash, swfSize, -+- &flashVer, &subscribepath, &usherToken, dSeek, dStopOffset, bLiveStream, timeout); -++ &tcUrl, &swfUrl, &pageUrl, &app, &auth, &swfHash, swfSize, -++ &flashVer, &subscribepath, &usherToken, &WeebToken, &ccomm, -++ dSeek, dStopOffset, bLiveStream, timeout); -+ } -+ else -+ { -+diff --git rtmpgw.c rtmpgw.c -+index 3e47602..e56b855 100644 -+--- rtmpgw.c -++++ rtmpgw.c -+@@ -96,7 +96,9 @@ typedef struct -+ AVal flashVer; -+ AVal token; -+ AVal subscribepath; -+- AVal usherToken; //Justin.tv auth token -++ AVal ccomm; -++ AVal usherToken; // Justin.tv auth token -++ AVal WeebToken; // Weeb.tv auth token -+ AVal sockshost; -+ AMFObject extras; -+ int edepth; -+@@ -556,8 +558,8 @@ void processTCPrequest(STREAMING_SERVER * server, // server socket and state (ou -+ if (!req.fullUrl.av_len) -+ { -+ RTMP_SetupStream(&rtmp, req.protocol, &req.hostname, req.rtmpport, &req.sockshost, -+- &req.playpath, &req.tcUrl, &req.swfUrl, &req.pageUrl, &req.app, &req.auth, &req.swfHash, req.swfSize, &req.flashVer, &req.subscribepath, &req.usherToken, dSeek, req.dStopOffset, -+- req.bLiveStream, req.timeout); -++ &req.playpath, &req.tcUrl, &req.swfUrl, &req.pageUrl, &req.app, &req.auth, &req.swfHash, req.swfSize, &req.flashVer, &req.subscribepath, -++ &req.usherToken, &req.WeebToken, &req.ccomm, dSeek, req.dStopOffset, req.bLiveStream, req.timeout); -+ } -+ else -+ { -+@@ -972,6 +974,12 @@ ParseOption(char opt, char *arg, RTMP_REQUEST * req) -+ case 'j': -+ STR2AVAL(req->usherToken, arg); -+ break; -++ case 'J': -++ STR2AVAL(req->WeebToken, arg); -++ break; -++ case 'K': -++ STR2AVAL(req->ccomm, arg); -++ break; -+ default: -+ RTMP_LogPrintf("unknown option: %c, arg: %s\n", opt, arg); -+ return FALSE; -+@@ -1044,6 +1052,8 @@ main(int argc, char **argv) -+ {"quiet", 0, NULL, 'q'}, -+ {"verbose", 0, NULL, 'V'}, -+ {"jtv", 1, NULL, 'j'}, -++ {"weeb", 1, NULL, 'J'}, -++ {"ccommand", 1, NULL, 'K'}, -+ {0, 0, 0, 0} -+ }; -+ -+@@ -1056,7 +1066,7 @@ main(int argc, char **argv) -+ -+ while ((opt = -+ getopt_long(argc, argv, -+- "hvqVzr:s:t:i:p:a:f:u:n:c:l:y:m:d:D:A:B:T:g:w:x:W:X:S:j:", longopts, -++ "hvqVzr:s:t:i:p:a:f:u:n:c:l:y:m:d:D:A:B:T:g:w:x:W:X:S:j:J:", longopts, -+ NULL)) != -1) -+ { -+ switch (opt) -+@@ -1119,8 +1129,12 @@ main(int argc, char **argv) -+ RTMP_LogPrintf -+ ("--token|-T key Key for SecureToken response\n"); -+ RTMP_LogPrintf -++ ("--ccommand|-K key Send custom command before play\n"); -++ RTMP_LogPrintf -+ ("--jtv|-j JSON Authentication token for Justin.tv legacy servers\n"); -+ RTMP_LogPrintf -++ ("--weeb|-J string Authentication token for weeb.tv servers\n"); -++ RTMP_LogPrintf -+ ("--buffer|-b Buffer time in milliseconds (default: %u)\n\n", -+ defaultRTMPRequest.bufferTime); -+ -+diff --git rtmpsrv.c rtmpsrv.c -+index 5df4d3a..eccaa9c 100644 -+--- rtmpsrv.c -++++ rtmpsrv.c -+@@ -25,9 +25,13 @@ -+ */ -+ -+ #include -++#ifdef __MINGW_H -++#include -++#endif -+ #include -+ #include -+ #include -++#include -+ -+ #include -+ #include -+@@ -94,12 +98,19 @@ typedef struct -+ STREAMING_SERVER *rtmpServer = 0; // server structure pointer -+ void *sslCtx = NULL; -+ -++int file_exists(const char *fname); -+ STREAMING_SERVER *startStreaming(const char *address, int port); -+ void stopStreaming(STREAMING_SERVER * server); -+ void AVreplace(AVal *src, const AVal *orig, const AVal *repl); -+ -+ static const AVal av_dquote = AVC("\""); -+ static const AVal av_escdquote = AVC("\\\""); -++#ifdef WIN32 -++static const AVal av_caret = AVC("^"); -++static const AVal av_esccaret = AVC("^^"); -++static const AVal av_pipe = AVC("|"); -++static const AVal av_escpipe = AVC("^|"); -++#endif -+ -+ typedef struct -+ { -+@@ -168,6 +179,12 @@ SAVC(level); -+ SAVC(code); -+ SAVC(description); -+ SAVC(secureToken); -++SAVC(_checkbw); -++SAVC(_onbwdone); -++SAVC(checkBandwidth); -++SAVC(onBWDone); -++SAVC(FCSubscribe); -++SAVC(onFCSubscribe); -+ -+ static int -+ SendConnectResult(RTMP *r, double txn) -+@@ -191,7 +208,7 @@ SendConnectResult(RTMP *r, double txn) -+ enc = AMF_EncodeNumber(enc, pend, txn); -+ *enc++ = AMF_OBJECT; -+ -+- STR2AVAL(av, "FMS/3,5,1,525"); -++ STR2AVAL(av, "FMS/3,5,7,7009"); -+ enc = AMF_EncodeNamedString(enc, pend, &av_fmsVer, &av); -+ enc = AMF_EncodeNamedNumber(enc, pend, &av_capabilities, 31.0); -+ enc = AMF_EncodeNamedNumber(enc, pend, &av_mode, 1.0); -+@@ -213,7 +230,7 @@ SendConnectResult(RTMP *r, double txn) -+ enc = AMF_EncodeNamedString(enc, pend, &av_secureToken, &av); -+ #endif -+ STR2AVAL(p.p_name, "version"); -+- STR2AVAL(p.p_vu.p_aval, "3,5,1,525"); -++ STR2AVAL(p.p_vu.p_aval, "3,5,7,7009"); -+ p.p_type = AMF_STRING; -+ obj.o_num = 1; -+ obj.o_props = &p; -+@@ -234,7 +251,7 @@ static int -+ SendResultNumber(RTMP *r, double txn, double ID) -+ { -+ RTMPPacket packet; -+- char pbuf[256], *pend = pbuf+sizeof(pbuf); -++ char pbuf[1024], *pend = pbuf + sizeof (pbuf); -+ -+ packet.m_nChannel = 0x03; // control channel (invoke) -+ packet.m_headerType = 1; /* RTMP_PACKET_SIZE_MEDIUM; */ -+@@ -264,12 +281,13 @@ static const AVal av_Stopped_playing = AVC("Stopped playing"); -+ SAVC(details); -+ SAVC(clientid); -+ static const AVal av_NetStream_Authenticate_UsherToken = AVC("NetStream.Authenticate.UsherToken"); -++static const AVal av_FCSubscribe_message = AVC("FCSubscribe to stream"); -+ -+ static int -+ SendPlayStart(RTMP *r) -+ { -+ RTMPPacket packet; -+- char pbuf[512], *pend = pbuf+sizeof(pbuf); -++ char pbuf[1024], *pend = pbuf + sizeof (pbuf); -+ -+ packet.m_nChannel = 0x03; // control channel (invoke) -+ packet.m_headerType = 1; /* RTMP_PACKET_SIZE_MEDIUM; */ -+@@ -301,7 +319,7 @@ static int -+ SendPlayStop(RTMP *r) -+ { -+ RTMPPacket packet; -+- char pbuf[512], *pend = pbuf+sizeof(pbuf); -++ char pbuf[1024], *pend = pbuf + sizeof (pbuf); -+ -+ packet.m_nChannel = 0x03; // control channel (invoke) -+ packet.m_headerType = 1; /* RTMP_PACKET_SIZE_MEDIUM; */ -+@@ -329,6 +347,83 @@ SendPlayStop(RTMP *r) -+ return RTMP_SendPacket(r, &packet, FALSE); -+ } -+ -++static int -++SendCheckBWResponse(RTMP *r, int oldMethodType, int onBWDoneInit) -++{ -++ RTMPPacket packet; -++ char pbuf[1024], *pend = pbuf + sizeof (pbuf); -++ char *enc; -++ -++ packet.m_nChannel = 0x03; /* control channel (invoke) */ -++ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM; -++ packet.m_packetType = RTMP_PACKET_TYPE_INVOKE; -++ packet.m_nTimeStamp = 0; -++ packet.m_nInfoField2 = 0; -++ packet.m_hasAbsTimestamp = 0; -++ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE; -++ -++ enc = packet.m_body; -++ if (oldMethodType) -++ { -++ enc = AMF_EncodeString(enc, pend, &av__onbwdone); -++ enc = AMF_EncodeNumber(enc, pend, 0); -++ *enc++ = AMF_NULL; -++ enc = AMF_EncodeNumber(enc, pend, 10240); -++ enc = AMF_EncodeNumber(enc, pend, 0); -++ } -++ else -++ { -++ enc = AMF_EncodeString(enc, pend, &av_onBWDone); -++ enc = AMF_EncodeNumber(enc, pend, 0); -++ *enc++ = AMF_NULL; -++ if (!onBWDoneInit) -++ { -++ enc = AMF_EncodeNumber(enc, pend, 10240); -++ enc = AMF_EncodeNumber(enc, pend, 0); -++ enc = AMF_EncodeNumber(enc, pend, 0); -++ enc = AMF_EncodeNumber(enc, pend, 20); -++ } -++ } -++ -++ packet.m_nBodySize = enc - packet.m_body; -++ -++ return RTMP_SendPacket(r, &packet, FALSE); -++} -++ -++static int -++SendOnFCSubscribe(RTMP *r) -++{ -++ RTMPPacket packet; -++ char pbuf[1024], *pend = pbuf + sizeof (pbuf); -++ char *enc; -++ -++ packet.m_nChannel = 0x03; /* control channel (invoke) */ -++ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM; -++ packet.m_packetType = RTMP_PACKET_TYPE_INVOKE; -++ packet.m_nTimeStamp = 0; -++ packet.m_nInfoField2 = 0; -++ packet.m_hasAbsTimestamp = 0; -++ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE; -++ -++ enc = packet.m_body; -++ enc = AMF_EncodeString(enc, pend, &av_onFCSubscribe); -++ enc = AMF_EncodeNumber(enc, pend, 0); -++ *enc++ = AMF_NULL; -++ -++ *enc++ = AMF_OBJECT; -++ enc = AMF_EncodeNamedString(enc, pend, &av_level, &av_status); -++ enc = AMF_EncodeNamedString(enc, pend, &av_code, &av_NetStream_Play_Start); -++ enc = AMF_EncodeNamedString(enc, pend, &av_description, &av_FCSubscribe_message); -++ enc = AMF_EncodeNamedNumber(enc, pend, &av_clientid, 0); -++ *enc++ = 0; -++ *enc++ = 0; -++ *enc++ = AMF_OBJECT_END; -++ -++ packet.m_nBodySize = enc - packet.m_body; -++ -++ return RTMP_SendPacket(r, &packet, FALSE); -++} -++ -+ static void -+ spawn_dumper(int argc, AVal *av, char *cmd) -+ { -+@@ -389,6 +484,8 @@ countAMF(AMFObject *obj, int *argc) -+ len += 40; -+ break; -+ case AMF_OBJECT: -++ case AMF_ECMA_ARRAY: -++ case AMF_STRICT_ARRAY: -+ len += 9; -+ len += countAMF(&p->p_vu.p_object, argc); -+ (*argc) += 2; -+@@ -407,9 +504,11 @@ dumpAMF(AMFObject *obj, char *ptr, AVal *argv, int *argc) -+ int i, ac = *argc; -+ const char opt[] = "NBSO Z"; -+ -+- for (i=0; i < obj->o_num; i++) -++ for (i = 0; i < obj->o_num; i++) -+ { -+ AMFObjectProperty *p = &obj->o_props[i]; -++ if ((p->p_type == AMF_ECMA_ARRAY) || (p->p_type == AMF_STRICT_ARRAY)) -++ p->p_type = AMF_OBJECT; -+ argv[ac].av_val = ptr+1; -+ argv[ac++].av_len = 2; -+ ptr += sprintf(ptr, " -C "); -+@@ -569,6 +668,7 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int -+ server->arglen += countAMF(&r->Link.extras, &server->argc); -+ } -+ SendConnectResult(r, txn); -++ SendCheckBWResponse(r, FALSE, TRUE); -+ } -+ else if (AVMATCH(&method, &av_createStream)) -+ { -+@@ -583,10 +683,26 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int -+ AVal usherToken; -+ AMFProp_GetString(AMF_GetProp(&obj, NULL, 3), &usherToken); -+ AVreplace(&usherToken, &av_dquote, &av_escdquote); -++#ifdef WIN32 -++ AVreplace(&usherToken, &av_caret, &av_esccaret); -++ AVreplace(&usherToken, &av_pipe, &av_escpipe); -++#endif -+ server->arglen += 6 + usherToken.av_len; -+ server->argc += 2; -+ r->Link.usherToken = usherToken; -+ } -++ else if (AVMATCH(&method, &av__checkbw)) -++ { -++ SendCheckBWResponse(r, TRUE, FALSE); -++ } -++ else if (AVMATCH(&method, &av_checkBandwidth)) -++ { -++ SendCheckBWResponse(r, FALSE, FALSE); -++ } -++ else if (AVMATCH(&method, &av_FCSubscribe)) -++ { -++ SendOnFCSubscribe(r); -++ } -+ else if (AVMATCH(&method, &av_play)) -+ { -+ char *file, *p, *q, *cmd, *ptr; -+@@ -602,6 +718,17 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int -+ if (obj.o_num > 5) -+ r->Link.length = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 5)); -+ */ -++ double StartFlag = 0; -++ AMFObjectProperty *Start = AMF_GetProp(&obj, NULL, 4); -++ if (!(Start->p_type == AMF_INVALID)) -++ StartFlag = AMFProp_GetNumber(Start); -++ r->Link.app = AVcopy(r->Link.app); -++ if (StartFlag == -1000 || (r->Link.app.av_val && strstr(r->Link.app.av_val, "live"))) -++ { -++ StartFlag = -1000; -++ server->arglen += 7; -++ server->argc += 1; -++ } -+ if (r->Link.tcUrl.av_len) -+ { -+ len = server->arglen + r->Link.playpath.av_len + 4 + -+@@ -619,6 +746,7 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int -+ argv[argc].av_val = ptr + 1; -+ argv[argc++].av_len = 2; -+ argv[argc].av_val = ptr + 5; -++ r->Link.tcUrl = StripParams(&r->Link.tcUrl); -+ ptr += sprintf(ptr," -r \"%s\"", r->Link.tcUrl.av_val); -+ argv[argc++].av_len = r->Link.tcUrl.av_len; -+ -+@@ -643,6 +771,7 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int -+ argv[argc].av_val = ptr + 1; -+ argv[argc++].av_len = 2; -+ argv[argc].av_val = ptr + 5; -++ r->Link.swfUrl = StripParams(&r->Link.swfUrl); -+ ptr += sprintf(ptr, " -W \"%s\"", r->Link.swfUrl.av_val); -+ argv[argc++].av_len = r->Link.swfUrl.av_len; -+ } -+@@ -665,10 +794,17 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int -+ r->Link.usherToken.av_val = NULL; -+ r->Link.usherToken.av_len = 0; -+ } -+- if (r->Link.extras.o_num) { -+- ptr = dumpAMF(&r->Link.extras, ptr, argv, &argc); -+- AMF_Reset(&r->Link.extras); -+- } -++ if (StartFlag == -1000) -++ { -++ argv[argc].av_val = ptr + 1; -++ argv[argc++].av_len = 6; -++ ptr += sprintf(ptr, " --live"); -++ } -++ if (r->Link.extras.o_num) -++ { -++ ptr = dumpAMF(&r->Link.extras, ptr, argv, &argc); -++ AMF_Reset(&r->Link.extras); -++ } -+ argv[argc].av_val = ptr + 1; -+ argv[argc++].av_len = 2; -+ argv[argc].av_val = ptr + 5; -+@@ -676,7 +812,13 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int -+ r->Link.playpath.av_len, r->Link.playpath.av_val); -+ argv[argc++].av_len = r->Link.playpath.av_len; -+ -+- av = r->Link.playpath; -++ if (r->Link.playpath.av_len) -++ av = r->Link.playpath; -++ else -++ { -++ av.av_val = "file"; -++ av.av_len = 4; -++ } -+ /* strip trailing URL parameters */ -+ q = memchr(av.av_val, '?', av.av_len); -+ if (q) -+@@ -710,25 +852,82 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int -+ -+ memcpy(file, av.av_val, av.av_len); -+ file[av.av_len] = '\0'; -+- for (p=file; *p; p++) -+- if (*p == ':') -+- *p = '_'; -+ -+- /* Add extension if none present */ -+- if (file[av.av_len - 4] != '.') -+- { -+- av.av_len += 4; -+- } -+- /* Always use flv extension, regardless of original */ -+- if (strcmp(file+av.av_len-4, ".flv")) -+- { -+- strcpy(file+av.av_len-4, ".flv"); -+- } -++ if (strlen(file) < 128) -++ { -++ /* Add extension if none present */ -++ if (file[av.av_len - 4] != '.') -++ { -++ av.av_len += 4; -++ } -++ -++ /* Always use flv extension, regardless of original */ -++ if (strcmp(file + av.av_len - 4, ".flv")) -++ { -++ strcpy(file + av.av_len - 4, ".flv"); -++ } -++ -++ /* Remove invalid characters from filename */ -++ file = strreplace(file, 0, ":", "_", TRUE); -++ file = strreplace(file, 0, "&", "_", TRUE); -++ file = strreplace(file, 0, "^", "_", TRUE); -++ file = strreplace(file, 0, "|", "_", TRUE); -++ } -++ else -++ { -++ /* Filename too long - generate unique name */ -++ strcpy(file, "vXXXXXX"); -++ mkstemp(file); -++ strcat(file, ".flv"); -++ } -++ -++ /* Add timestamp to the filename */ -++ char *filename, *pfilename, timestamp[21]; -++ int filename_len, timestamp_len; -++ time_t current_time; -++ -++ time(¤t_time); -++ timestamp_len = strftime(×tamp[0], sizeof (timestamp), "%Y-%m-%d_%I-%M-%S_", localtime(¤t_time)); -++ timestamp[timestamp_len] = '\0'; -++ filename_len = strlen(file); -++ filename = malloc(timestamp_len + filename_len + 1); -++ pfilename = filename; -++ memcpy(pfilename, timestamp, timestamp_len); -++ pfilename += timestamp_len; -++ memcpy(pfilename, file, filename_len); -++ pfilename += filename_len; -++ *pfilename++ = '\0'; -++ file = filename; -++ -+ argv[argc].av_val = ptr + 1; -+ argv[argc++].av_len = 2; -+ argv[argc].av_val = file; -+ argv[argc].av_len = av.av_len; -+- ptr += sprintf(ptr, " -o %s", file); -++#ifdef VLC -++ char *vlc; -++ int didAlloc = FALSE; -++ -++ if (getenv("VLC")) -++ vlc = getenv("VLC"); -++ else if (getenv("ProgramFiles")) -++ { -++ vlc = malloc(512 * sizeof (char)); -++ didAlloc = TRUE; -++ char *ProgramFiles = getenv("ProgramFiles"); -++ sprintf(vlc, "\"%s%s", ProgramFiles, " (x86)\\VideoLAN\\VLC\\vlc.exe"); -++ if (!file_exists(vlc + 1)) -++ sprintf(vlc + 1, "%s%s", ProgramFiles, "\\VideoLAN\\VLC\\vlc.exe"); -++ strcpy(vlc + strlen(vlc), "\" -"); -++ } -++ else -++ vlc = "vlc -"; -++ -++ ptr += sprintf(ptr, " | %s", vlc); -++ if (didAlloc) -++ free(vlc); -++#else -++ ptr += sprintf(ptr, " -o \"%s\"", file); -++#endif -+ now = RTMP_GetTime(); -+ if (now - server->filetime < DUPTIME && AVMATCH(&argv[argc], &server->filename)) -+ { -+@@ -742,7 +941,21 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int -+ server->filetime = now; -+ free(server->filename.av_val); -+ server->filename = argv[argc++]; -+- spawn_dumper(argc, argv, cmd); -++#ifdef VLC -++ FILE *vlc_cmdfile = fopen("VLC.bat", "w"); -++ char *vlc_batchcmd = strreplace(cmd, 0, "%", "%%", FALSE); -++ fprintf(vlc_cmdfile, "%s\n", vlc_batchcmd); -++ fclose(vlc_cmdfile); -++ free(vlc_batchcmd); -++ spawn_dumper(argc, argv, "VLC.bat"); -++#else -++ spawn_dumper(argc, argv, cmd); -++#endif -++ -++ /* Save command to text file */ -++ FILE *cmdfile = fopen("Command.txt", "a"); -++ fprintf(cmdfile, "%s\n", cmd); -++ fclose(cmdfile); -+ } -+ -+ free(cmd); -+@@ -861,12 +1074,18 @@ controlServerThread(void *unused) -+ { -+ case 'q': -+ RTMP_LogPrintf("Exiting\n"); -+- stopStreaming(rtmpServer); -+- exit(0); -++ if (rtmpServer) -++ stopStreaming(rtmpServer); -+ break; -+ default: -+ RTMP_LogPrintf("Unknown command \'%c\', ignoring\n", ich); -+ } -++ sleep(1); -++ if (rtmpServer && (rtmpServer->state == STREAMING_STOPPED)) -++ { -++ RTMP_Log(RTMP_LOGDEBUG, "Exiting text UI thread"); -++ break; -++ } -+ } -+ TFRET(); -+ } -+@@ -1054,7 +1273,6 @@ stopStreaming(STREAMING_SERVER * server) -+ } -+ } -+ -+- -+ void -+ sigIntHandler(int sig) -+ { -+@@ -1191,3 +1409,15 @@ AVreplace(AVal *src, const AVal *orig, const AVal *repl) -+ src->av_val = dest; -+ src->av_len = dptr - dest; -+ } -++ -++int -++file_exists(const char *fname) -++{ -++ FILE *file; -++ if ((file = fopen(fname, "r"))) -++ { -++ fclose(file); -++ return TRUE; -++ } -++ return FALSE; -++} -+diff --git rtmpsuck.c rtmpsuck.c -+index e886179..0abdba4 100644 -+--- rtmpsuck.c -++++ rtmpsuck.c -+@@ -25,10 +25,13 @@ -+ */ -+ -+ #include -++#ifdef __MINGW_H -++#include -++#endif -+ #include -+ #include -+ #include -+- -++#include -+ #include -+ #include -+ -+@@ -141,18 +144,21 @@ SAVC(code); -+ SAVC(secureToken); -+ SAVC(onStatus); -+ SAVC(close); -++SAVC(play2); -+ static const AVal av_NetStream_Failed = AVC("NetStream.Failed"); -+ static const AVal av_NetStream_Play_Failed = AVC("NetStream.Play.Failed"); -+-static const AVal av_NetStream_Play_StreamNotFound = -+-AVC("NetStream.Play.StreamNotFound"); -+-static const AVal av_NetConnection_Connect_InvalidApp = -+-AVC("NetConnection.Connect.InvalidApp"); -++static const AVal av_NetStream_Play_StreamNotFound = AVC("NetStream.Play.StreamNotFound"); -++static const AVal av_NetConnection_Connect_InvalidApp = AVC("NetConnection.Connect.InvalidApp"); -++static const AVal av_NetConnection_Connect_Rejected = AVC("NetConnection.Connect.Rejected"); -+ static const AVal av_NetStream_Play_Start = AVC("NetStream.Play.Start"); -+ static const AVal av_NetStream_Play_Complete = AVC("NetStream.Play.Complete"); -+ static const AVal av_NetStream_Play_Stop = AVC("NetStream.Play.Stop"); -++static const AVal av_NetStream_Authenticate_UsherToken = AVC("NetStream.Authenticate.UsherToken"); -+ -+ static const char *cst[] = { "client", "server" }; -+ -++char *dumpAMF(AMFObject *obj, char *ptr); -++ -+ // Returns 0 for OK/Failed/error, 1 for 'Stop or Complete' -+ int -+ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *body) -+@@ -198,26 +204,28 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b -+ if (cobj.o_props[i].p_type == AMF_STRING) -+ { -+ pval = cobj.o_props[i].p_vu.p_aval; -+- RTMP_LogPrintf("%.*s: %.*s\n", pname.av_len, pname.av_val, pval.av_len, pval.av_val); -++ RTMP_LogPrintf("%10.*s : %.*s\n", pname.av_len, pname.av_val, pval.av_len, pval.av_val); -+ } -+ if (AVMATCH(&pname, &av_app)) -+ { -+- server->rc.Link.app = pval; -++ server->rc.Link.app = AVcopy(pval); -+ pval.av_val = NULL; -+ } -+ else if (AVMATCH(&pname, &av_flashVer)) -+ { -+- server->rc.Link.flashVer = pval; -++ server->rc.Link.flashVer = AVcopy(pval); -+ pval.av_val = NULL; -+ } -+ else if (AVMATCH(&pname, &av_swfUrl)) -+ { -+ #ifdef CRYPTO -+ if (pval.av_val) -+- RTMP_HashSWF(pval.av_val, &server->rc.Link.SWFSize, -+- (unsigned char *)server->rc.Link.SWFHash, 30); -++ { -++ AVal swfUrl = StripParams(&pval); -++ RTMP_HashSWF(swfUrl.av_val, &server->rc.Link.SWFSize, (unsigned char *) server->rc.Link.SWFHash, 30); -++ } -+ #endif -+- server->rc.Link.swfUrl = pval; -++ server->rc.Link.swfUrl = AVcopy(pval); -+ pval.av_val = NULL; -+ } -+ else if (AVMATCH(&pname, &av_tcUrl)) -+@@ -225,7 +233,7 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b -+ char *r1 = NULL, *r2; -+ int len; -+ -+- server->rc.Link.tcUrl = pval; -++ server->rc.Link.tcUrl = AVcopy(pval); -+ if ((pval.av_val[0] | 0x40) == 'r' && -+ (pval.av_val[1] | 0x40) == 't' && -+ (pval.av_val[2] | 0x40) == 'm' && -+@@ -267,7 +275,7 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b -+ } -+ else if (AVMATCH(&pname, &av_pageUrl)) -+ { -+- server->rc.Link.pageUrl = pval; -++ server->rc.Link.pageUrl = AVcopy(pval); -+ pval.av_val = NULL; -+ } -+ else if (AVMATCH(&pname, &av_audioCodecs)) -+@@ -287,14 +295,21 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b -+ if (pval.av_val) -+ free(pval.av_val); -+ } -++ -+ if (obj.o_num > 3) -+ { -+- if (AMFProp_GetBoolean(&obj.o_props[3])) -+- server->rc.Link.lFlags |= RTMP_LF_AUTH; -+- if (obj.o_num > 4) -+- { -+- AMFProp_GetString(&obj.o_props[4], &server->rc.Link.auth); -+- } -++ int i = obj.o_num - 3; -++ server->rc.Link.extras.o_num = i; -++ server->rc.Link.extras.o_props = malloc(i * sizeof (AMFObjectProperty)); -++ memcpy(server->rc.Link.extras.o_props, obj.o_props + 3, i * sizeof (AMFObjectProperty)); -++ obj.o_num = 3; -++ } -++ -++ if (server->rc.Link.extras.o_num) -++ { -++ server->rc.Link.Extras.av_val = calloc(2048, sizeof (char)); -++ dumpAMF(&server->rc.Link.extras, server->rc.Link.Extras.av_val); -++ server->rc.Link.Extras.av_len = strlen(server->rc.Link.Extras.av_val); -+ } -+ -+ if (!RTMP_Connect(&server->rc, pack)) -+@@ -303,6 +318,37 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b -+ return 1; -+ } -+ server->rc.m_bSendCounter = FALSE; -++ -++ if (server->rc.Link.extras.o_props) -++ { -++ AMF_Reset(&server->rc.Link.extras); -++ } -++ } -++ else if (AVMATCH(&method, &av_NetStream_Authenticate_UsherToken)) -++ { -++ AVal usherToken = {0}; -++ AMFProp_GetString(AMF_GetProp(&obj, NULL, 3), &usherToken); -++ server->rc.Link.usherToken = AVcopy(usherToken); -++ RTMP_LogPrintf("%10s : %.*s\n", "usherToken", server->rc.Link.usherToken.av_len, server->rc.Link.usherToken.av_val); -++ } -++ else if (AVMATCH(&method, &av_play2)) -++ { -++ RTMP_Log(RTMP_LOGDEBUG, "%s: Detected play2 request\n", __FUNCTION__); -++ if (body && nBodySize > 0) -++ { -++ char* pCmd = (char*) body; -++ char* pEnd = pCmd + nBodySize - 4; -++ while (pCmd < pEnd) -++ { -++ if (pCmd[0] == 'p' && pCmd[1] == 'l' && pCmd[2] == 'a' && pCmd[3] == 'y' && pCmd[4] == '2') -++ { -++ /* Disable bitrate transition by sending invalid command */ -++ pCmd[4] = 'z'; -++ break; -++ } -++ ++pCmd; -++ } -++ } -+ } -+ else if (AVMATCH(&method, &av_play)) -+ { -+@@ -323,6 +369,14 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b -+ if (!av.av_val) -+ goto out; -+ -++ double StartFlag = 0; -++ AMFObjectProperty *Start = AMF_GetProp(&obj, NULL, 4); -++ if (!(Start->p_type == AMF_INVALID)) -++ StartFlag = AMFProp_GetNumber(Start); -++ if (StartFlag == -1000 || (server->rc.Link.app.av_val && strstr(server->rc.Link.app.av_val, "live"))) -++ StartFlag = -1000; -++ RTMP_LogPrintf("%10s : %s\n", "live", (StartFlag == -1000) ? "yes" : "no"); -++ -+ /* check for duplicates */ -+ for (fl = server->f_head; fl; fl=fl->f_next) -+ { -+@@ -362,19 +416,104 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b -+ /* hope there aren't more than 255 dups */ -+ if (count) -+ flen += 2; -+- file = malloc(flen+1); -++ file = malloc(flen + 5); -+ -+ memcpy(file, av.av_val, av.av_len); -+ if (count) -+ sprintf(file+av.av_len, "%02x", count); -+ else -+ file[av.av_len] = '\0'; -+- for (p=file; *p; p++) -+- if (*p == ':') -+- *p = '_'; -+- RTMP_LogPrintf("Playpath: %.*s\nSaving as: %s\n", -+- server->rc.Link.playpath.av_len, server->rc.Link.playpath.av_val, -+- file); -++ -++ if (strlen(file) < 128) -++ { -++ /* Add extension if none present */ -++ if (file[av.av_len - 4] != '.') -++ { -++ av.av_len += 4; -++ } -++ -++ /* Always use flv extension, regardless of original */ -++ if (strcmp(file + av.av_len - 4, ".flv")) -++ { -++ strcpy(file + av.av_len - 4, ".flv"); -++ } -++ -++ /* Remove invalid characters from filename */ -++ file = strreplace(file, 0, ":", "_", TRUE); -++ file = strreplace(file, 0, "&", "_", TRUE); -++ file = strreplace(file, 0, "^", "_", TRUE); -++ file = strreplace(file, 0, "|", "_", TRUE); -++ } -++ else -++ { -++ /* Filename too long - generate unique name */ -++ strcpy(file, "vXXXXXX"); -++ mkstemp(file); -++ strcat(file, ".flv"); -++ } -++ -++ /* Add timestamp to the filename */ -++ char *filename, *pfilename, timestamp[21]; -++ int filename_len, timestamp_len; -++ time_t current_time; -++ -++ time(¤t_time); -++ timestamp_len = strftime(×tamp[0], sizeof (timestamp), "%Y-%m-%d_%I-%M-%S_", localtime(¤t_time)); -++ timestamp[timestamp_len] = '\0'; -++ filename_len = strlen(file); -++ filename = malloc(timestamp_len + filename_len + 1); -++ pfilename = filename; -++ memcpy(pfilename, timestamp, timestamp_len); -++ pfilename += timestamp_len; -++ memcpy(pfilename, file, filename_len); -++ pfilename += filename_len; -++ *pfilename++ = '\0'; -++ file = filename; -++ -++ RTMP_LogPrintf("%10s : %.*s\n%10s : %s\n", "Playpath", server->rc.Link.playpath.av_len, -++ server->rc.Link.playpath.av_val, "Saving as", file); -++ -++ /* Save command to text file */ -++ char *cmd = NULL, *ptr = NULL; -++ AVal swfUrl, tcUrl; -++ -++ cmd = calloc(4096, sizeof (char)); -++ ptr = cmd; -++ tcUrl = StripParams(&server->rc.Link.tcUrl); -++ swfUrl = StripParams(&server->rc.Link.swfUrl); -++ ptr += sprintf(ptr, "rtmpdump -r \"%.*s\" -a \"%.*s\" -f \"%.*s\" -W \"%.*s\" -p \"%.*s\"", -++ tcUrl.av_len, tcUrl.av_val, -++ server->rc.Link.app.av_len, server->rc.Link.app.av_val, -++ server->rc.Link.flashVer.av_len, server->rc.Link.flashVer.av_val, -++ swfUrl.av_len, swfUrl.av_val, -++ server->rc.Link.pageUrl.av_len, server->rc.Link.pageUrl.av_val); -++ -++ if (server->rc.Link.usherToken.av_val) -++ { -++ char *usherToken = strreplace(server->rc.Link.usherToken.av_val, server->rc.Link.usherToken.av_len, "\"", "\\\"", TRUE); -++#ifdef WIN32 -++ usherToken = strreplace(usherToken, 0, "^", "^^", TRUE); -++ usherToken = strreplace(usherToken, 0, "|", "^|", TRUE); -++#endif -++ ptr += sprintf(ptr, " --jtv \"%s\"", usherToken); -++ free(usherToken); -++ } -++ -++ if (server->rc.Link.Extras.av_len) -++ { -++ ptr += sprintf(ptr, "%.*s", server->rc.Link.Extras.av_len, server->rc.Link.Extras.av_val); -++ } -++ -++ if (StartFlag == -1000) -++ ptr += sprintf(ptr, "%s", " --live"); -++ ptr += sprintf(ptr, " -y \"%.*s\"", server->rc.Link.playpath.av_len, server->rc.Link.playpath.av_val); -++ ptr += sprintf(ptr, " -o \"%s\"\n", file); -++ -++ FILE *cmdfile = fopen("Command.txt", "a"); -++ fprintf(cmdfile, "%s", cmd); -++ fclose(cmdfile); -++ free(cmd); -++ -+ out = fopen(file, "wb"); -+ free(file); -+ if (!out) -+@@ -407,9 +546,10 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b -+ -+ RTMP_Log(RTMP_LOGDEBUG, "%s, onStatus: %s", __FUNCTION__, code.av_val); -+ if (AVMATCH(&code, &av_NetStream_Failed) -+- || AVMATCH(&code, &av_NetStream_Play_Failed) -+- || AVMATCH(&code, &av_NetStream_Play_StreamNotFound) -+- || AVMATCH(&code, &av_NetConnection_Connect_InvalidApp)) -++ || AVMATCH(&code, &av_NetStream_Play_Failed) -++ || AVMATCH(&code, &av_NetStream_Play_StreamNotFound) -++ || AVMATCH(&code, &av_NetConnection_Connect_Rejected) -++ || AVMATCH(&code, &av_NetConnection_Connect_InvalidApp)) -+ { -+ ret = 1; -+ } -+@@ -719,13 +859,18 @@ controlServerThread(void *unused) -+ { -+ case 'q': -+ RTMP_LogPrintf("Exiting\n"); -+- stopStreaming(rtmpServer); -+- free(rtmpServer); -+- exit(0); -++ if (rtmpServer) -++ stopStreaming(rtmpServer); -+ break; -+ default: -+ RTMP_LogPrintf("Unknown command \'%c\', ignoring\n", ich); -+ } -++ sleep(1); -++ if (rtmpServer && (rtmpServer->state == STREAMING_STOPPED)) -++ { -++ RTMP_Log(RTMP_LOGDEBUG, "Exiting text UI thread"); -++ break; -++ } -+ } -+ TFRET(); -+ } -+@@ -815,7 +960,7 @@ TFTYPE doServe(void *arg) // server socket and state (our listening socket) -+ -+ if (select(n + 1, &rfds, NULL, NULL, &tv) <= 0) -+ { -+- if (server->f_cur && server->rc.m_mediaChannel && !paused) -++ if (server->f_cur && server->rc.m_mediaChannel && !paused && server->rc.m_channelTimestamp) -+ { -+ server->rc.m_pauseStamp = server->rc.m_channelTimestamp[server->rc.m_mediaChannel]; -+ if (RTMP_ToggleStream(&server->rc)) -+@@ -1123,7 +1268,6 @@ stopStreaming(STREAMING_SERVER * server) -+ } -+ } -+ -+- -+ void -+ sigIntHandler(int sig) -+ { -+@@ -1196,3 +1340,48 @@ main(int argc, char **argv) -+ #endif -+ return nStatus; -+ } -++ -++char * -++dumpAMF(AMFObject *obj, char *ptr) -++{ -++ int i; -++ const char opt[] = "NBSO Z"; -++ -++ for (i = 0; i < obj->o_num; i++) -++ { -++ AMFObjectProperty *p = &obj->o_props[i]; -++ if ((p->p_type == AMF_ECMA_ARRAY) || (p->p_type == AMF_STRICT_ARRAY)) -++ p->p_type = AMF_OBJECT; -++ if (p->p_type > 5) -++ continue; -++ ptr += sprintf(ptr, " -C "); -++ if (p->p_name.av_val) -++ *ptr++ = 'N'; -++ *ptr++ = opt[p->p_type]; -++ *ptr++ = ':'; -++ if (p->p_name.av_val) -++ ptr += sprintf(ptr, "%.*s:", p->p_name.av_len, p->p_name.av_val); -++ switch (p->p_type) -++ { -++ case AMF_BOOLEAN: -++ *ptr++ = p->p_vu.p_number != 0 ? '1' : '0'; -++ break; -++ case AMF_STRING: -++ memcpy(ptr, p->p_vu.p_aval.av_val, p->p_vu.p_aval.av_len); -++ ptr += p->p_vu.p_aval.av_len; -++ break; -++ case AMF_NUMBER: -++ ptr += sprintf(ptr, "%f", p->p_vu.p_number); -++ break; -++ case AMF_OBJECT: -++ *ptr++ = '1'; -++ ptr = dumpAMF(&p->p_vu.p_object, ptr); -++ ptr += sprintf(ptr, " -C O:0"); -++ break; -++ case AMF_NULL: -++ default: -++ break; -++ } -++ } -++ return ptr; -++} -+diff --git thread.c thread.c -+index 0913c98..13d624a 100644 -+--- thread.c -++++ thread.c -+@@ -32,7 +32,7 @@ ThreadCreate(thrfunc *routine, void *args) -+ HANDLE thd; -+ -+ thd = (HANDLE) _beginthread(routine, 0, args); -+- if (thd == -1L) -++ if (thd == INVALID_HANDLE_VALUE) -+ RTMP_LogPrintf("%s, _beginthread failed with %d\n", __FUNCTION__, errno); -+ -+ return thd; -diff --git a/tools/depends/target/librtmp/UpdateToLatest.diff b/tools/depends/target/librtmp/UpdateToLatest.diff -new file mode 100644 -index 0000000000000000000000000000000000000000..d9d5f6b8e4869efaba4b03abef4ccb534c4e8beb ---- /dev/null -+++ b/tools/depends/target/librtmp/UpdateToLatest.diff -@@ -0,0 +1,257 @@ -+diff --git b/ChangeLog a/ChangeLog -+index c3b1a14..b027e31 100644 -+--- b/ChangeLog -++++ a/ChangeLog -+@@ -1,6 +1,6 @@ -+ RTMPDump -+ Copyright 2008-2009 Andrej Stepanchuk; Distributed under the GPL v2 -+-Copyright 2009-2011 Howard Chu -++Copyright 2009-2015 Howard Chu -+ Copyright 2009 The Flvstreamer Team -+ http://rtmpdump.mplayerhq.hu/ -+ -+diff --git b/librtmp/amf.c a/librtmp/amf.c -+index 73d1486..7954144 100644 -+--- b/librtmp/amf.c -++++ a/librtmp/amf.c -+@@ -33,6 +33,7 @@ -+ #include "bytes.h" -+ -+ static const AMFObjectProperty AMFProp_Invalid = { {0, 0}, AMF_INVALID }; -++static const AMFObject AMFObj_Invalid = { 0, 0 }; -+ static const AVal AV_empty = { 0, 0 }; -+ -+ /* Data is Big-Endian */ -+@@ -340,13 +341,19 @@ AMFProp_GetBoolean(AMFObjectProperty *prop) -+ void -+ AMFProp_GetString(AMFObjectProperty *prop, AVal *str) -+ { -+- *str = prop->p_vu.p_aval; -++ if (prop->p_type == AMF_STRING) -++ *str = prop->p_vu.p_aval; -++ else -++ *str = AV_empty; -+ } -+ -+ void -+ AMFProp_GetObject(AMFObjectProperty *prop, AMFObject *obj) -+ { -+- *obj = prop->p_vu.p_object; -++ if (prop->p_type == AMF_OBJECT) -++ *obj = prop->p_vu.p_object; -++ else -++ *obj = AMFObj_Invalid; -+ } -+ -+ int -+@@ -471,6 +478,8 @@ AMF3ReadString(const char *data, AVal *str) -+ RTMP_Log(RTMP_LOGDEBUG, -+ "%s, string reference, index: %d, not supported, ignoring!", -+ __FUNCTION__, refIndex); -++ str->av_val = NULL; -++ str->av_len = 0; -+ return len; -+ } -+ else -+@@ -510,9 +519,11 @@ AMF3Prop_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize, -+ if (name.av_len <= 0) -+ return nRes; -+ -++ nSize -= nRes; -++ if (nSize <= 0) -++ return -1; -+ prop->p_name = name; -+ pBuffer += nRes; -+- nSize -= nRes; -+ } -+ -+ /* decode */ -+@@ -598,6 +609,8 @@ AMF3Prop_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize, -+ __FUNCTION__, (unsigned char)(*pBuffer), pBuffer); -+ return -1; -+ } -++ if (nSize < 0) -++ return -1; -+ -+ return nOriginalSize - nSize; -+ } -+@@ -992,9 +1005,17 @@ AMF_DecodeArray(AMFObject *obj, const char *pBuffer, int nSize, -+ int nRes; -+ nArrayLen--; -+ -++ if (nSize <= 0) -++ { -++ bError = TRUE; -++ break; -++ } -+ nRes = AMFProp_Decode(&prop, pBuffer, nSize, bDecodeName); -+ if (nRes == -1) -+- bError = TRUE; -++ { -++ bError = TRUE; -++ break; -++ } -+ else -+ { -+ nSize -= nRes; -+@@ -1053,12 +1074,12 @@ AMF3_Decode(AMFObject *obj, const char *pBuffer, int nSize, int bAMFData) -+ else -+ { -+ int32_t classExtRef = (classRef >> 1); -+- int i; -++ int i, cdnum; -+ -+ cd.cd_externalizable = (classExtRef & 0x1) == 1; -+ cd.cd_dynamic = ((classExtRef >> 1) & 0x1) == 1; -+ -+- cd.cd_num = classExtRef >> 2; -++ cdnum = classExtRef >> 2; -+ -+ /* class name */ -+ -+@@ -1073,9 +1094,16 @@ AMF3_Decode(AMFObject *obj, const char *pBuffer, int nSize, int bAMFData) -+ cd.cd_name.av_val, cd.cd_externalizable, cd.cd_dynamic, -+ cd.cd_num); -+ -+- for (i = 0; i < cd.cd_num; i++) -++ for (i = 0; i < cdnum; i++) -+ { -+ AVal memberName; -++ if (nSize <=0) -++ { -++invalid: -++ RTMP_Log(RTMP_LOGDEBUG, "%s, invalid class encoding!", -++ __FUNCTION__); -++ return nOriginalSize; -++ } -+ len = AMF3ReadString(pBuffer, &memberName); -+ RTMP_Log(RTMP_LOGDEBUG, "Member: %s", memberName.av_val); -+ AMF3CD_AddProp(&cd, &memberName); -+@@ -1111,6 +1139,8 @@ AMF3_Decode(AMFObject *obj, const char *pBuffer, int nSize, int bAMFData) -+ int nRes, i; -+ for (i = 0; i < cd.cd_num; i++) /* non-dynamic */ -+ { -++ if (nSize <=0) -++ goto invalid; -+ nRes = AMF3Prop_Decode(&prop, pBuffer, nSize, FALSE); -+ if (nRes == -1) -+ RTMP_Log(RTMP_LOGDEBUG, "%s, failed to decode AMF3 property!", -+@@ -1128,6 +1158,8 @@ AMF3_Decode(AMFObject *obj, const char *pBuffer, int nSize, int bAMFData) -+ -+ do -+ { -++ if (nSize <=0) -++ goto invalid; -+ nRes = AMF3Prop_Decode(&prop, pBuffer, nSize, TRUE); -+ AMF_AddProp(obj, &prop); -+ -+@@ -1175,10 +1207,18 @@ AMF_Decode(AMFObject *obj, const char *pBuffer, int nSize, int bDecodeName) -+ -+ nRes = AMFProp_Decode(&prop, pBuffer, nSize, bDecodeName); -+ if (nRes == -1) -+- bError = TRUE; -++ { -++ bError = TRUE; -++ break; -++ } -+ else -+ { -+ nSize -= nRes; -++ if (nSize < 0) -++ { -++ bError = TRUE; -++ break; -++ } -+ pBuffer += nRes; -+ AMF_AddProp(obj, &prop); -+ } -+diff --git b/librtmp/log.c a/librtmp/log.c -+index 0012985..1b52000 100644 -+--- b/librtmp/log.c -++++ a/librtmp/log.c -+@@ -92,6 +92,10 @@ RTMP_LogLevel RTMP_LogGetLevel() -+ void RTMP_Log(int level, const char *format, ...) -+ { -+ va_list args; -++ -++ if ( level > RTMP_debuglevel ) -++ return; -++ -+ va_start(args, format); -+ cb(level, format, args); -+ va_end(args); -+diff --git b/librtmp/rtmp.c a/librtmp/rtmp.c -+index ca7db6a..a2863b0 100644 -+--- b/librtmp/rtmp.c -++++ a/librtmp/rtmp.c -+@@ -186,9 +186,12 @@ RTMPPacket_Reset(RTMPPacket *p) -+ } -+ -+ int -+-RTMPPacket_Alloc(RTMPPacket *p, int nSize) -++RTMPPacket_Alloc(RTMPPacket *p, uint32_t nSize) -+ { -+- char *ptr = calloc(1, nSize + RTMP_MAX_HEADER_SIZE); -++ char *ptr; -++ if (nSize > SIZE_MAX - RTMP_MAX_HEADER_SIZE) -++ return FALSE; -++ ptr = calloc(1, nSize + RTMP_MAX_HEADER_SIZE); -+ if (!ptr) -+ return FALSE; -+ p->m_body = ptr + RTMP_MAX_HEADER_SIZE; -+@@ -1180,7 +1183,7 @@ RTMP_GetNextMediaPacket(RTMP *r, RTMPPacket *packet) -+ while (!bHasMediaPacket && RTMP_IsConnected(r) -+ && RTMP_ReadPacket(r, packet)) -+ { -+- if (!RTMPPacket_IsReady(packet)) -++ if (!RTMPPacket_IsReady(packet) || !packet->m_nBodySize) -+ { -+ continue; -+ } -+@@ -3643,7 +3646,6 @@ RTMP_ReadPacket(RTMP *r, RTMPPacket *packet) -+ { -+ packet->m_nBodySize = AMF_DecodeInt24(header + 3); -+ packet->m_nBytesRead = 0; -+- RTMPPacket_Free(packet); -+ -+ if (nSize > 6) -+ { -+diff --git b/librtmp/rtmp.h a/librtmp/rtmp.h -+index 0248913..6d7dd89 100644 -+--- b/librtmp/rtmp.h -++++ a/librtmp/rtmp.h -+@@ -136,7 +136,7 @@ extern "C" -+ -+ void RTMPPacket_Reset(RTMPPacket *p); -+ void RTMPPacket_Dump(RTMPPacket *p); -+- int RTMPPacket_Alloc(RTMPPacket *p, int nSize); -++ int RTMPPacket_Alloc(RTMPPacket *p, uint32_t nSize); -+ void RTMPPacket_Free(RTMPPacket *p); -+ -+ #define RTMPPacket_IsReady(a) ((a)->m_nBytesRead == (a)->m_nBodySize) -+diff --git b/rtmpsrv.c a/rtmpsrv.c -+index a9e9045..5df4d3a 100644 -+--- b/rtmpsrv.c -++++ a/rtmpsrv.c -+@@ -404,10 +404,10 @@ countAMF(AMFObject *obj, int *argc) -+ static char * -+ dumpAMF(AMFObject *obj, char *ptr, AVal *argv, int *argc) -+ { -+- int i, len, ac = *argc; -++ int i, ac = *argc; -+ const char opt[] = "NBSO Z"; -+ -+- for (i=0, len=0; i < obj->o_num; i++) -++ for (i=0; i < obj->o_num; i++) -+ { -+ AMFObjectProperty *p = &obj->o_props[i]; -+ argv[ac].av_val = ptr+1; -+@@ -595,6 +595,8 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int -+ uint32_t now; -+ RTMPPacket pc = {0}; -+ AMFProp_GetString(AMF_GetProp(&obj, NULL, 3), &r->Link.playpath); -++ if (!r->Link.playpath.av_len) -++ return 0; -+ /* -+ r->Link.seekTime = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 4)); -+ if (obj.o_num > 5) -diff --git a/tools/depends/target/librtmp/libm.patch b/tools/depends/target/librtmp/libm.patch -deleted file mode 100644 -index d86485b584920d3b8e7d775196e50f9b7fe3b297..0000000000000000000000000000000000000000 ---- a/tools/depends/target/librtmp/libm.patch -+++ /dev/null -@@ -1,11 +0,0 @@ ----- Makefile.old 2013-06-04 17:35:58.000000000 +0200 --+++ Makefile 2013-06-04 17:36:13.000000000 +0200 --@@ -25,7 +25,7 @@ -- REQ_GNUTLS=gnutls -- REQ_OPENSSL=libssl,libcrypto -- LIBZ=-lz ---LIBS_posix= --+LIBS_posix=-lm -- LIBS_darwin= -- LIBS_mingw=-lws2_32 -lwinmm -lgdi32 -- LIB_GNUTLS=-lgnutls -lhogweed -lnettle -lgmp $(LIBZ) - -From 2c9b195f2c8cf3559bba7d7b21d35ee0d0bca59c Mon Sep 17 00:00:00 2001 +From a3fffaef5c155d74ff051a7bbb2c1b56449ece13 Mon Sep 17 00:00:00 2001 From: Claudio-Sjo Date: Mon, 16 Feb 2015 14:51:26 +0100 -Subject: [PATCH 23/67] - allow reads < CDIO_CD_FRAMESIZE_RAW by using a buffer +Subject: [PATCH 21/61] - allow reads < CDIO_CD_FRAMESIZE_RAW by using a buffer - fixes #15794 --- @@ -6615,10 +2149,10 @@ index 0427af4534bfe59a343f0518c7f4242d93299836..e99236294fa8b9b613e465a8ecaf3ad3 lsn_t m_lsnCurrent; // Position inside the track in logical sector number lsn_t m_lsnEnd; // End of m_iTrack in logical sector number -From d83b2890c3b4135d505f202f9081f59a1fd7b065 Mon Sep 17 00:00:00 2001 +From 60a1b2ccb05742807a0fcbceaf5da47c8c13a66f Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 24 Jun 2016 19:38:13 +0100 -Subject: [PATCH 24/67] codecoverlay: Include codec name in overlay +Subject: [PATCH 22/61] codecoverlay: Include codec name in overlay --- xbmc/cores/VideoPlayer/VideoPlayerAudio.cpp | 4 ++++ @@ -6644,7 +2178,7 @@ index 24228154ecf99911f74407d73d280778e6f98fcd..188b85b12b86f887324cdcfda3c3aa4c //print the inverse of the resample ratio, since that makes more sense //if the resample ratio is 0.5, then we're playing twice as fast diff --git a/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp b/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp -index fd260d4378f6b13a158a57a2493e59cbab1f7d9d..f6d1b8572c6a4a8b4a193ebfc9d36d85ccd2d819 100644 +index fee65c3bd9ccdb3b7fc6e677c0473dfdd3d131bc..11ffffb23b435b1ea77fc756cf321013393f9f4a 100644 --- a/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp +++ b/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp @@ -909,10 +909,13 @@ int CVideoPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) @@ -6678,7 +2212,7 @@ index 1e5d2b98bbef15b47994c3e4735873a9946b58c7..d43350fa0eefb5960475a02c1327efc2 return s.str(); } diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -index 6efd0d51df46a530dd05b3add639f38a939cf92d..d61dc4f2668f8aca91bce79cfb631034061c491c 100644 +index f9fa18aa9dfea0d50be09947439e56219f1f9b3d..6cd7d243d0fbea08c33e81edb5a51ab402bd110d 100644 --- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp +++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp @@ -583,12 +583,14 @@ void OMXPlayerVideo::SetSpeed(int speed) @@ -6712,10 +2246,10 @@ index 0df7e72cc9d1947173c2bac5e72eb09976b51aa5..b5050081c360d29b1b478c27e6b88291 double m_iSubtitleDelay; bool m_bRenderSubs; -From e46e93d403ab9f6cb6f61a5b7ac39f347bcf6089 Mon Sep 17 00:00:00 2001 +From 34b921907166a74b1f941cb54e6437bbddc50e1e Mon Sep 17 00:00:00 2001 From: Anton Fedchin Date: Tue, 8 Mar 2016 21:20:58 +0300 -Subject: [PATCH 25/67] [DebugInfo] Add cpu usage info. +Subject: [PATCH 23/61] [DebugInfo] Add cpu usage info. --- .../VideoPlayer/VideoRenderers/DebugRenderer.cpp | 56 ++++++++-------------- @@ -6852,7 +2386,7 @@ index 85aefaace73994730f7d2bdff9de85c79e99b2a2..8005a13bc220be0c5c596d276197c11e }; \ No newline at end of file diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp -index 93f8d6f292accf34e153fa4d3dd982e5a4b4fded..db537d33a5d55fc856bbd3ec0a7846df3bb060be 100644 +index 558a1f3df9ac82f3c7f32a91a1f2235c7f6563c6..f2a133e1ff7b440ebc741878ccf87e6da090aa8c 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp +++ b/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp @@ -24,6 +24,7 @@ @@ -6863,7 +2397,7 @@ index 93f8d6f292accf34e153fa4d3dd982e5a4b4fded..db537d33a5d55fc856bbd3ec0a7846df #include "utils/log.h" #include "utils/StringUtils.h" #include "windowing/WindowingFactory.h" -@@ -926,7 +927,7 @@ void CRenderManager::Render(bool clear, DWORD flags, DWORD alpha, bool gui) +@@ -922,7 +923,7 @@ void CRenderManager::Render(bool clear, DWORD flags, DWORD alpha, bool gui) if (m_renderDebug) { @@ -6872,7 +2406,7 @@ index 93f8d6f292accf34e153fa4d3dd982e5a4b4fded..db537d33a5d55fc856bbd3ec0a7846df m_playerPort->GetDebugInfo(audio, video, player); -@@ -940,8 +941,10 @@ void CRenderManager::Render(bool clear, DWORD flags, DWORD alpha, bool gui) +@@ -936,8 +937,10 @@ void CRenderManager::Render(bool clear, DWORD flags, DWORD alpha, bool gui) missedvblanks, clockspeed - 100.0); } @@ -6885,10 +2419,10 @@ index 93f8d6f292accf34e153fa4d3dd982e5a4b4fded..db537d33a5d55fc856bbd3ec0a7846df m_debugTimer.Set(1000); -From e674b4137eb3ffe70a0bae619e24862ceae51b25 Mon Sep 17 00:00:00 2001 +From 5732950f2b9b5c9488bf669fc1dabfe773098900 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 22 May 2015 13:56:29 +0100 -Subject: [PATCH 26/67] ffmpeg: Allow neon to be enabled in unified builds +Subject: [PATCH 24/61] ffmpeg: Allow neon to be enabled in unified builds --- tools/depends/target/ffmpeg/Makefile | 4 ++++ @@ -6911,17 +2445,17 @@ index dffe2da1dfd09e06c5f15c362f7cbe3cf2a26f75..4081dddb6bc2db53559d35506cad6af4 ifeq ($(OS), linux) ffmpg_config += --target-os=$(OS) --cpu=$(CPU) -From c575384e34c27d1ffb70e0181e45bc4078b1d2ac Mon Sep 17 00:00:00 2001 +From 2bdca30180c30357bf1ad3f2266622acc44605a9 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 27 Feb 2015 14:37:27 +0000 -Subject: [PATCH 27/67] ffmpeg: Add some upstream HEVC optimisations +Subject: [PATCH 25/61] ffmpeg: Add some upstream HEVC optimisations --- tools/depends/target/ffmpeg/Makefile | 6 +- .../added_ARM_NEON_optimized_SAO_patches.patch | 3328 ++++++++++++++++++++ - tools/depends/target/ffmpeg/autobuild.sh | 3 + + tools/depends/target/ffmpeg/autobuild.sh | 2 + ...hevcdsp_ARM_NEON_optimized_epel_functions.patch | 409 +++ - 4 files changed, 3745 insertions(+), 1 deletion(-) + 4 files changed, 3744 insertions(+), 1 deletion(-) create mode 100644 tools/depends/target/ffmpeg/added_ARM_NEON_optimized_SAO_patches.patch create mode 100644 tools/depends/target/ffmpeg/hevcdsp_ARM_NEON_optimized_epel_functions.patch @@ -10284,16 +5818,15 @@ index 0000000000000000000000000000000000000000..792b5fea581613a6fe9108443357f975 +2.5.0 + diff --git a/tools/depends/target/ffmpeg/autobuild.sh b/tools/depends/target/ffmpeg/autobuild.sh -index 9c26b239c2b2c1221bed7c4d99c46e909a4a5c5d..b9590d7b200a2ccf0fe3aa660e3b08b82d2133fc 100755 +index e491c788793fa5df35e4570b54d7606183350376..1a169999f75813a3f8e18185ced0620d445dee1f 100755 --- a/tools/depends/target/ffmpeg/autobuild.sh +++ b/tools/depends/target/ffmpeg/autobuild.sh -@@ -128,6 +128,9 @@ cd "ffmpeg-${VERSION}" || exit 2 +@@ -128,6 +128,8 @@ cd "ffmpeg-${VERSION}" || exit 2 tar --strip-components=1 -xf $MYDIR/${ARCHIVE} - patch -p1 < ../../0001-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patch -+patch -p1 < ../../0001-Discard-data-before-VO-VOL-in-mpeg-4-over-mpegts.patch -+patch -p1 < ../../hevcdsp_ARM_NEON_optimized_epel_functions.patch -+patch -p1 < ../../added_ARM_NEON_optimized_SAO_patches.patch + patch -p1 < ../0001-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patch ++patch -p1 < ../hevcdsp_ARM_NEON_optimized_epel_functions.patch ++patch -p1 < ../added_ARM_NEON_optimized_SAO_patches.patch CFLAGS="$CFLAGS" CXXFLAGS="$CXXFLAGS" LDFLAGS="$LDFLAGS" \ ./configure --prefix=$FFMPEG_PREFIX \ @@ -10713,10 +6246,10 @@ index 0000000000000000000000000000000000000000..5e8e07d407f045fc99554f0f061d1e81 +2.5.0 + -From 641013389142290475c0c053cf2cbd3a4866eae0 Mon Sep 17 00:00:00 2001 +From 68dcdd8420309caf7e4f7896b5c27df98705590c Mon Sep 17 00:00:00 2001 From: popcornmix Date: Thu, 7 May 2015 14:04:18 +0100 -Subject: [PATCH 28/67] [ffmpeg] Add GPU acceleration to hevc +Subject: [PATCH 26/61] [ffmpeg] Add GPU acceleration to hevc --- tools/depends/target/ffmpeg/Makefile | 4 +- @@ -10748,14 +6281,14 @@ index d9db534dd8c59a4993a3509737d901fbb3923de8..2dc4addea504d142eb74385653584bf3 cd $(PLATFORM);\ CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" CPPFLAGS="$(CPPFLAGS)" LDFLAGS="$(LDFLAGS)" \ diff --git a/tools/depends/target/ffmpeg/autobuild.sh b/tools/depends/target/ffmpeg/autobuild.sh -index b9590d7b200a2ccf0fe3aa660e3b08b82d2133fc..b6bd57731bca6dfe5f814a4043b3e08d1bb08318 100755 +index 1a169999f75813a3f8e18185ced0620d445dee1f..e2641093d15e5b465fae7e5f87c3ea18573dd6ee 100755 --- a/tools/depends/target/ffmpeg/autobuild.sh +++ b/tools/depends/target/ffmpeg/autobuild.sh -@@ -131,6 +131,7 @@ patch -p1 < ../../0001-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patc - patch -p1 < ../../0001-Discard-data-before-VO-VOL-in-mpeg-4-over-mpegts.patch - patch -p1 < ../../hevcdsp_ARM_NEON_optimized_epel_functions.patch - patch -p1 < ../../added_ARM_NEON_optimized_SAO_patches.patch -+patch -p1 < ../../pfcd_hevc_optimisations.patch +@@ -130,6 +130,7 @@ tar --strip-components=1 -xf $MYDIR/${ARCHIVE} + patch -p1 < ../0001-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patch + patch -p1 < ../hevcdsp_ARM_NEON_optimized_epel_functions.patch + patch -p1 < ../added_ARM_NEON_optimized_SAO_patches.patch ++patch -p1 < ../pfcd_hevc_optimisations.patch CFLAGS="$CFLAGS" CXXFLAGS="$CXXFLAGS" LDFLAGS="$LDFLAGS" \ ./configure --prefix=$FFMPEG_PREFIX \ @@ -48902,10 +44435,10 @@ index 0000000000000000000000000000000000000000..e172ebf157aebffe1ae50b4a2b25fd71 +2.7.4 + -From 4dcf6adc09c509c7e448a4fcfe48bc7da6f907a8 Mon Sep 17 00:00:00 2001 +From 8d0b79d79bc31d6f84ee57e9b40b45dbe92be56d Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sat, 22 Aug 2015 23:06:56 +0100 -Subject: [PATCH 29/67] [dvdmessage] Increase timeout on +Subject: [PATCH 27/61] [dvdmessage] Increase timeout on CDVDMsgGeneralSynchronize --- @@ -48913,23 +44446,23 @@ Subject: [PATCH 29/67] [dvdmessage] Increase timeout on 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xbmc/cores/VideoPlayer/DVDMessage.cpp b/xbmc/cores/VideoPlayer/DVDMessage.cpp -index 5aed6918d217df884107fe6366b3668efa96af20..2442fc808ae89c5550b8db34b2605f5037f2ef29 100644 +index 0dcc664fd862706c60659f3664c7d964597c94d5..7614c831af9dfc821121a4111546fd4dfc664d06 100644 --- a/xbmc/cores/VideoPlayer/DVDMessage.cpp +++ b/xbmc/cores/VideoPlayer/DVDMessage.cpp @@ -90,7 +90,7 @@ bool CDVDMsgGeneralSynchronize::Wait(unsigned int milliseconds, unsigned int sou - void CDVDMsgGeneralSynchronize::Wait(volatile bool *abort, unsigned int source) + void CDVDMsgGeneralSynchronize::Wait(std::atomic& abort, unsigned int source) { -- while(!Wait(100, source)) -+ while(!Wait(200, source)) - { - if(abort && *abort) - return; +- while(!Wait(100, source) && !abort); ++ while(!Wait(200, source) && !abort); + } + + long CDVDMsgGeneralSynchronize::Release() -From 01bce0b478e428f0e8805868222928e8274bb809 Mon Sep 17 00:00:00 2001 +From 3ccd3f7c40d9211b26df3479d89e931eb4ff3a95 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 16 Sep 2015 19:05:12 +0100 -Subject: [PATCH 30/67] [3d] Make MVC a valid 3D filename tag +Subject: [PATCH 28/61] [3d] Make MVC a valid 3D filename tag --- xbmc/guilib/StereoscopicsManager.cpp | 9 +++++++++ @@ -48958,10 +44491,10 @@ index b34873cba6534086ae243326550385867a03256a..1443acaf0f25df458ae49766e13dd032 } diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp -index 446293308010f3b8cd8d325fa6d0285fcc9f892d..ae21da29314ae8faa35129a79e62e82b55fbc306 100644 +index 03f566d3ee4eab690d2236b7739080269d552511..60e5652f69e96a559d8080e01dc214a56fb19343 100644 --- a/xbmc/settings/AdvancedSettings.cpp +++ b/xbmc/settings/AdvancedSettings.cpp -@@ -403,6 +403,7 @@ void CAdvancedSettings::Initialize() +@@ -402,6 +402,7 @@ void CAdvancedSettings::Initialize() m_stereoscopicregex_3d = "[-. _]3d[-. _]"; m_stereoscopicregex_sbs = "[-. _]h?sbs[-. _]"; m_stereoscopicregex_tab = "[-. _]h?tab[-. _]"; @@ -48969,7 +44502,7 @@ index 446293308010f3b8cd8d325fa6d0285fcc9f892d..ae21da29314ae8faa35129a79e62e82b m_useDisplayControlHWStereo = false; -@@ -517,6 +518,7 @@ void CAdvancedSettings::ParseSettingsFile(const std::string &file) +@@ -516,6 +517,7 @@ void CAdvancedSettings::ParseSettingsFile(const std::string &file) XMLUtils::GetString(pElement, "stereoscopicregex3d", m_stereoscopicregex_3d); XMLUtils::GetString(pElement, "stereoscopicregexsbs", m_stereoscopicregex_sbs); XMLUtils::GetString(pElement, "stereoscopicregextab", m_stereoscopicregex_tab); @@ -48978,10 +44511,10 @@ index 446293308010f3b8cd8d325fa6d0285fcc9f892d..ae21da29314ae8faa35129a79e62e82b XMLUtils::GetFloat(pElement, "audiodelayrange", m_videoAudioDelayRange, 10, 600); XMLUtils::GetString(pElement, "defaultplayer", m_videoDefaultPlayer); diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h -index bcbd5d1c68b576034a418dd2dce0b47071229e0b..d4a30863806eb1c86042e0991793aedf20bf8344 100644 +index 1727580c0c8de2b6fda19a741f90721a570b96b8..4fa973515df6e677418a6bf7f9d0b4a31c022c0a 100644 --- a/xbmc/settings/AdvancedSettings.h +++ b/xbmc/settings/AdvancedSettings.h -@@ -372,6 +372,7 @@ class CAdvancedSettings : public ISettingCallback, public ISettingsHandler +@@ -371,6 +371,7 @@ class CAdvancedSettings : public ISettingCallback, public ISettingsHandler std::string m_stereoscopicregex_3d; std::string m_stereoscopicregex_sbs; std::string m_stereoscopicregex_tab; @@ -48990,10 +44523,10 @@ index bcbd5d1c68b576034a418dd2dce0b47071229e0b..d4a30863806eb1c86042e0991793aedf bool m_useDisplayControlHWStereo; -From 6268ac7405bc4f407e486644d11383f30e48c952 Mon Sep 17 00:00:00 2001 +From 55dd622a6608b801350e62955c891a6a78a3e8e9 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 5 Oct 2015 14:58:05 +0100 -Subject: [PATCH 31/67] [3d] Swap top/bottom sides of GUI +Subject: [PATCH 29/61] [3d] Swap top/bottom sides of GUI --- xbmc/guilib/GraphicContext.cpp | 2 +- @@ -49013,10 +44546,10 @@ index 9caa43113f63139d277bd71242a858a581736845..3ace73527a7c359ac21c87bf38b5d648 } if(m_stereoMode == RENDER_STEREO_MODE_SPLIT_VERTICAL) -From 97e700d5324b40fc895f1cbcf656ad4291ecfbee Mon Sep 17 00:00:00 2001 +From 79e39f5976fccbf9e9699b60b4f45a5f59d19bb5 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 11 Oct 2015 20:51:37 +0100 -Subject: [PATCH 32/67] Revert "Revert "Disable extra logging by default"" +Subject: [PATCH 30/61] Revert "Revert "Disable extra logging by default"" This reverts commit a880554325be187b877cd8f0e2b338e7267da636. --- @@ -49024,10 +44557,10 @@ This reverts commit a880554325be187b877cd8f0e2b338e7267da636. 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/settings/settings.xml b/system/settings/settings.xml -index ca7e8892606782e54d4883c5b2f0e6686b1ae280..b67d1113477541f5ce3533495a9960b8646b83ed 100644 +index 88b67c1869246037e81fb3efbe293f9fee37d25e..df60cf2d052f5a1570bd445468b156211a870007 100644 --- a/system/settings/settings.xml +++ b/system/settings/settings.xml -@@ -2649,12 +2649,12 @@ +@@ -2672,12 +2672,12 @@ 1 @@ -49043,32 +44576,32 @@ index ca7e8892606782e54d4883c5b2f0e6686b1ae280..b67d1113477541f5ce3533495a9960b8 loggingcomponents , -From 52605aac1a6ca5d9a77513d6467935e7795c540a Mon Sep 17 00:00:00 2001 +From e18e8f939792d196c85b36c1e65a0ec4bb00bfc3 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Thu, 26 Nov 2015 17:14:49 +0000 -Subject: [PATCH 33/67] [ae] Add debug logging showing resamplerate +Subject: [PATCH 31/61] [ae] Add debug logging showing resamplerate --- xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp -index 5bb87b2764fdf1606f438fb3a008b322f8adf271..f9e8a9beaa9b3b4590c698a4d64351cb14c2339d 100644 +index 5196c62cd005d6c52cd741fc523eb5b7cd4b625b..dc9a34059f0eca5287bf42a7a8f89910c35e84e3 100644 --- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp -@@ -2471,6 +2471,7 @@ CSampleBuffer* CActiveAE::SyncStream(CActiveAEStream *stream) - if (stream->m_resampleBuffers) +@@ -2451,6 +2451,7 @@ CSampleBuffer* CActiveAE::SyncStream(CActiveAEStream *stream) + if (stream->m_processingBuffers) { - stream->m_resampleBuffers->m_resampleRatio = stream->CalcResampleRatio(error); -+ CLog::Log(LOGDEBUG, "CDVDPlayerAudio::%s rr:%.5f error:%.6f", __FUNCTION__, stream->m_resampleBuffers->m_resampleRatio, error); + stream->m_processingBuffers->SetRR(stream->CalcResampleRatio(error)); ++ CLog::Log(LOGDEBUG, "CDVDPlayerAudio::%s rr:%.5f error:%.6f", __FUNCTION__, stream->m_processingBuffers->GetRR(), error); } } - else if (stream->m_resampleBuffers) + else if (stream->m_processingBuffers) -From 17b01a2c74a918d1d6fddc35d7b3a7da986d7225 Mon Sep 17 00:00:00 2001 +From 83909d8961c984556768c161a0d2db8ff88e271b Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 21 Dec 2015 22:17:25 +0000 -Subject: [PATCH 34/67] [omximage] Fall back to arm jpeg encode/decode when gpu +Subject: [PATCH 32/61] [omximage] Fall back to arm jpeg encode/decode when gpu is busy --- @@ -49311,10 +44844,10 @@ index a93aa82663903fb1bf712058c2e259290ee742e6..6f38dbc7e5cc721c59a3633935f08218 extern COMXImage g_OMXImage; -From 95d0673204e2559173405d03df038ac152a5501b Mon Sep 17 00:00:00 2001 +From 4eada6619f36a9cd27209354d2f771458a166dd4 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 9 Dec 2015 13:31:14 +0000 -Subject: [PATCH 35/67] [mmalcodec] Fail to open when width is invalid. Can +Subject: [PATCH 33/61] [mmalcodec] Fail to open when width is invalid. Can happen with mpegts files --- @@ -49322,10 +44855,10 @@ Subject: [PATCH 35/67] [mmalcodec] Fail to open when width is invalid. Can 1 file changed, 3 insertions(+) diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -index c0e553ca060749edff28bcbb880ed3e149b9f751..8691b086a46fcdd03eee809a53ea9b20f74dcc05 100644 +index c6f98ded45062617d88571cd70fc6336cfdc32c9..283b2626731c25c67e4c065dac7725a488c09523 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -@@ -541,6 +541,9 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) +@@ -368,6 +368,9 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) if (g_advancedSettings.CanLogComponent(LOGVIDEO)) CLog::Log(LOGDEBUG, "%s::%s usemmal:%d software:%d %dx%d renderer:%p", CLASSNAME, __func__, CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_USEMMAL), hints.software, hints.width, hints.height, options.m_opaque_pointer); @@ -49336,10 +44869,10 @@ index c0e553ca060749edff28bcbb880ed3e149b9f751..8691b086a46fcdd03eee809a53ea9b20 if (!CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_USEMMAL) || hints.software) return false; -From 9f2c6309ca9bcc281124fa0a5bdb665d9fb50f35 Mon Sep 17 00:00:00 2001 +From cad95d3b4d889687eab0da4da40549cbed5df09e Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 12 Jan 2016 16:29:57 +0000 -Subject: [PATCH 36/67] ffmpeg: Add cabac opimisations for hevc +Subject: [PATCH 34/61] ffmpeg: Add cabac opimisations for hevc --- .../0001-Squashed-commit-of-the-following.patch | 2179 ++++++++++++++++++++ @@ -51564,22 +47097,22 @@ index 2dc4addea504d142eb74385653584bf39b253156..d1d76cb2ce04d5fd056796cc133fceb3 cd $(PLATFORM);\ CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" CPPFLAGS="$(CPPFLAGS)" LDFLAGS="$(LDFLAGS)" \ diff --git a/tools/depends/target/ffmpeg/autobuild.sh b/tools/depends/target/ffmpeg/autobuild.sh -index b6bd57731bca6dfe5f814a4043b3e08d1bb08318..65800dfccc7cbf17124a96d81378b1c3ddf92342 100755 +index e2641093d15e5b465fae7e5f87c3ea18573dd6ee..7022b5fadef58ad27b61725d77131bd78af2f51d 100755 --- a/tools/depends/target/ffmpeg/autobuild.sh +++ b/tools/depends/target/ffmpeg/autobuild.sh -@@ -132,6 +132,7 @@ patch -p1 < ../../0001-Discard-data-before-VO-VOL-in-mpeg-4-over-mpegts.patch - patch -p1 < ../../hevcdsp_ARM_NEON_optimized_epel_functions.patch - patch -p1 < ../../added_ARM_NEON_optimized_SAO_patches.patch - patch -p1 < ../../pfcd_hevc_optimisations.patch -+patch -p1 < ../../0001-Squashed-commit-of-the-following.patch +@@ -131,6 +131,7 @@ patch -p1 < ../0001-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patch + patch -p1 < ../hevcdsp_ARM_NEON_optimized_epel_functions.patch + patch -p1 < ../added_ARM_NEON_optimized_SAO_patches.patch + patch -p1 < ../pfcd_hevc_optimisations.patch ++patch -p1 < ../0001-Squashed-commit-of-the-following.patch CFLAGS="$CFLAGS" CXXFLAGS="$CXXFLAGS" LDFLAGS="$LDFLAGS" \ ./configure --prefix=$FFMPEG_PREFIX \ -From 3dac5d0c77bfd3b88d90944154c058d1e6429bb8 Mon Sep 17 00:00:00 2001 +From ee0055a7424b344357a0a8dbcfc3524f841f31ff Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 19 Sep 2014 11:54:49 +0100 -Subject: [PATCH 37/67] [videoplayer/rbp] Add pi specific option to maintain +Subject: [PATCH 35/61] [videoplayer/rbp] Add pi specific option to maintain vsync with pll adjustment New A/V sync option in settings/video/playback to do "Adjust PLL". @@ -51601,10 +47134,10 @@ or drop/dupe audio packets which is normally required. 12 files changed, 122 insertions(+), 19 deletions(-) diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po -index 085e2a195d2e52ce6bea3ed791bf817f5be23b15..8cb9f8503c29c54cd0cb55018f867a45248c649f 100644 +index 3208dad8988fba4bce7687861037274a42ffd21f..b5ae4dc1a6b21ba96fd3498baff1b63004fa6902 100644 --- a/addons/resource.language.en_gb/resources/strings.po +++ b/addons/resource.language.en_gb/resources/strings.po -@@ -19417,3 +19417,35 @@ msgstr "" +@@ -19483,3 +19483,35 @@ msgstr "" msgctxt "#38190" msgid "Extract thumbnails from video files" msgstr "" @@ -51641,7 +47174,7 @@ index 085e2a195d2e52ce6bea3ed791bf817f5be23b15..8cb9f8503c29c54cd0cb55018f867a45 +msgid "Max" +msgstr "" diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml -index 737ec4e0c7f0feb98a6dd008b53e238c41dde8af..2e6c903df5e4d2cd064466db0ef55deada5cdc80 100644 +index 770c628a15304856504676af82d46d57c97b86b8..b7770ebc1b9568f9fe141d90a118b87106c86735 100644 --- a/system/settings/rbp.xml +++ b/system/settings/rbp.xml @@ -98,6 +98,20 @@ @@ -51666,7 +47199,7 @@ index 737ec4e0c7f0feb98a6dd008b53e238c41dde8af..2e6c903df5e4d2cd064466db0ef55dea diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp -index f9e8a9beaa9b3b4590c698a4d64351cb14c2339d..6a22f8145ce9dfb46f0ddae27eb0753413b066d3 100644 +index dc9a34059f0eca5287bf42a7a8f89910c35e84e3..8cbc09c2401865f04d20662ddb24d52e78a6219d 100644 --- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp @@ -34,6 +34,10 @@ using namespace ActiveAE; @@ -51696,7 +47229,7 @@ index f9e8a9beaa9b3b4590c698a4d64351cb14c2339d..6a22f8145ce9dfb46f0ddae27eb07534 par->stream->m_resampleIntegral = 0.0; } return; -@@ -2466,7 +2471,16 @@ CSampleBuffer* CActiveAE::SyncStream(CActiveAEStream *stream) +@@ -2446,7 +2451,16 @@ CSampleBuffer* CActiveAE::SyncStream(CActiveAEStream *stream) if (!newerror || stream->m_syncState != CAESyncInfo::AESyncState::SYNC_INSYNC) return ret; @@ -51712,9 +47245,9 @@ index f9e8a9beaa9b3b4590c698a4d64351cb14c2339d..6a22f8145ce9dfb46f0ddae27eb07534 + } + else if (stream->m_resampleMode) { - if (stream->m_resampleBuffers) + if (stream->m_processingBuffers) { -@@ -3322,13 +3336,14 @@ void CActiveAE::SetStreamResampleRatio(CActiveAEStream *stream, double ratio) +@@ -3302,13 +3316,14 @@ void CActiveAE::SetStreamResampleRatio(CActiveAEStream *stream, double ratio) &msg, sizeof(MsgStreamParameter)); } @@ -51761,10 +47294,10 @@ index 2a31a6e3c09fa61907ef9e518158773ba7d3b03e..3efc7afc255c542ea2aedbf83d6962be void SetStreamFade(CActiveAEStream *stream, float from, float target, unsigned int millis); diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp -index 1d58691db79e53a4a4cfb32c45f209a115853722..d1e8863cb9600bf1a026520f77501bb98e51918a 100644 +index 430bbf65d5cd68927018d8d7d01c144185fcd7fb..f9a9825bfe3b037047bbb63e9aefd379c2cf40e9 100644 --- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp -@@ -503,11 +503,12 @@ void CActiveAEStream::SetResampleRatio(double ratio) +@@ -509,11 +509,12 @@ void CActiveAEStream::SetResampleRatio(double ratio) m_streamResampleRatio = ratio; } @@ -51781,10 +47314,10 @@ index 1d58691db79e53a4a4cfb32c45f209a115853722..d1e8863cb9600bf1a026520f77501bb9 void CActiveAEStream::SetFFmpegInfo(int profile, enum AVMatrixEncoding matrix_encoding, enum AVAudioServiceType audio_service_type) diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.h -index 0fd959b8071e5a03d7749689e2e0042907d4d4bf..8b25159f198279f2515fe4f84fc9403dcb46c401 100644 +index b44227aca644e6af5cf8f33ca92ee1028d180413..65a6c38d1040647ca86deca4193572d283de6868 100644 --- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.h +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.h -@@ -137,7 +137,7 @@ public: +@@ -169,7 +169,7 @@ public: virtual double GetResampleRatio(); virtual void SetResampleRatio(double ratio); @@ -51793,7 +47326,7 @@ index 0fd959b8071e5a03d7749689e2e0042907d4d4bf..8b25159f198279f2515fe4f84fc9403d virtual void RegisterAudioCallback(IAudioCallback* pCallback); virtual void UnRegisterAudioCallback(); virtual void FadeVolume(float from, float to, unsigned int time); -@@ -154,6 +154,7 @@ protected: +@@ -186,6 +186,7 @@ protected: float m_streamAmplify; double m_streamResampleRatio; int m_streamResampleMode; @@ -51801,14 +47334,14 @@ index 0fd959b8071e5a03d7749689e2e0042907d4d4bf..8b25159f198279f2515fe4f84fc9403d unsigned int m_streamSpace; bool m_streamDraining; bool m_streamDrained; -@@ -194,6 +195,7 @@ protected: +@@ -226,6 +227,7 @@ protected: int m_fadingTime; int m_profile; int m_resampleMode; + float m_pllAdjust; double m_resampleIntegral; + double m_clockSpeed; enum AVMatrixEncoding m_matrixEncoding; - enum AVAudioServiceType m_audioServiceType; diff --git a/xbmc/cores/AudioEngine/Interfaces/AEStream.h b/xbmc/cores/AudioEngine/Interfaces/AEStream.h index 7416685ef766492b13bbbde9001f868f28907d34..e3dbc5f2ddd6269f5e80086d2fd04e1ae68ac828 100644 --- a/xbmc/cores/AudioEngine/Interfaces/AEStream.h @@ -51918,7 +47451,7 @@ index 188b85b12b86f887324cdcfda3c3aa4cd90d3a11..b05c4e4c6a2361455ab553133965aa20 if (!codec || codec->NeedPassthrough() == m_pAudioCodec->NeedPassthrough()) { // passthrough state has not changed diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp -index fbffa3a952d920cb41412f00f59d5c1c91f98740..d6591cc4e1938b231cd3ce9035ca9334dcffdde9 100644 +index 92f20e5174dd6b886cf622460ac68ab5f2fe24b9..3618a68143d30391f937eb4bfdb6ed09dd86b9ce 100644 --- a/xbmc/linux/RBP.cpp +++ b/xbmc/linux/RBP.cpp @@ -49,6 +49,7 @@ CRBP::CRBP() @@ -51975,10 +47508,10 @@ index 90b04db5405058be2ff20aeaa6af2d2ac651586f..084fba87f49f4c3b33a8dd4a20a626a3 void init_cursor(); void set_cursor(const void *pixels, int width, int height, int hotspot_x, int hotspot_y); -From d7f88d01cde2cd4b0894463321e1ff0c413d9446 Mon Sep 17 00:00:00 2001 +From dafa8df17474794163e7783cafecc1b9d5615e16 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Thu, 7 May 2015 15:35:43 +0100 -Subject: [PATCH 38/67] rbp: Support zero copy interface with hevc acceleration +Subject: [PATCH 36/61] rbp: Support zero copy interface with hevc acceleration --- xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 9 +++++++++ @@ -51986,10 +47519,10 @@ Subject: [PATCH 38/67] rbp: Support zero copy interface with hevc acceleration 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -index 967d5181a42f7cad0fe7b559a8eb958073a8144d..ec2d47d7443ab75af5ad119b8ae04fb072eca677 100644 +index 3ccf4b8cd92d9907653adda291d1124244963e1b..9216a91527478eb7f8a9062177596e9bb6319e52 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -@@ -306,6 +306,15 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options +@@ -308,6 +308,15 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options if (tryhw && m_decoderState == STATE_NONE) { m_decoderState = STATE_HW_SINGLE; @@ -52006,12 +47539,12 @@ index 967d5181a42f7cad0fe7b559a8eb958073a8144d..ec2d47d7443ab75af5ad119b8ae04fb0 else { diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALFFmpeg.cpp -index 3825e4cca4df7e1a791410b741aecc64823a3c69..e1bb3ab37f68b69e39fb00ab6e4785a430250173 100644 +index ad0f65cc64f545b32d1812c9e218c57ec6866b00..a5597c1386c5afdc6ec8f6840355557ee26e8950 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALFFmpeg.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALFFmpeg.cpp -@@ -355,8 +355,9 @@ bool CDecoder::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture - assert(!picture->MMALBuffer->mmal_buffer); - picture->MMALBuffer->mmal_buffer = mmal_buffer; +@@ -281,8 +281,9 @@ bool CDecoder::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture + picture->MMALBuffer->mmal_buffer->data = (uint8_t *)gmem->m_vc_handle; + picture->MMALBuffer->mmal_buffer->alloc_size = picture->MMALBuffer->mmal_buffer->length = gmem->m_numbytes; - // need to flush ARM cache so GPU can see it - gmem->Flush(); @@ -52022,10 +47555,10 @@ index 3825e4cca4df7e1a791410b741aecc64823a3c69..e1bb3ab37f68b69e39fb00ab6e4785a4 if (g_advancedSettings.CanLogComponent(LOGVIDEO)) CLog::Log(LOGDEBUG, "%s::%s - mmal:%p dts:%.3f pts:%.3f buf:%p gpu:%p", CLASSNAME, __FUNCTION__, picture->MMALBuffer->mmal_buffer, 1e-6*picture->dts, 1e-6*picture->pts, picture->MMALBuffer, gmem); -From 2b6121f39768cf5d22ffc73a475484519ac2881e Mon Sep 17 00:00:00 2001 +From 340049d662e9165d55def43f8d09bee5376752a4 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sat, 16 May 2015 18:26:04 +0100 -Subject: [PATCH 39/67] ffmpeg: use upstream mvc patches +Subject: [PATCH 37/61] ffmpeg: use upstream mvc patches --- ...vcodec-add-h264_mvc-codec-id-and-profiles.patch | 68 ++++++++++++ @@ -52260,16 +47793,16 @@ index d1d76cb2ce04d5fd056796cc133fceb3f3c246c9..92d9437b36eaa4e655990f7e68634e0b cd $(PLATFORM);\ CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" CPPFLAGS="$(CPPFLAGS)" LDFLAGS="$(LDFLAGS)" \ diff --git a/tools/depends/target/ffmpeg/autobuild.sh b/tools/depends/target/ffmpeg/autobuild.sh -index 65800dfccc7cbf17124a96d81378b1c3ddf92342..4217ea350aa93e4a7acbe9dd15c9f8699db383b8 100755 +index 7022b5fadef58ad27b61725d77131bd78af2f51d..0c323ac47f7f79f4ce786c29c8f58bccad5d96dd 100755 --- a/tools/depends/target/ffmpeg/autobuild.sh +++ b/tools/depends/target/ffmpeg/autobuild.sh -@@ -133,6 +133,9 @@ patch -p1 < ../../hevcdsp_ARM_NEON_optimized_epel_functions.patch - patch -p1 < ../../added_ARM_NEON_optimized_SAO_patches.patch - patch -p1 < ../../pfcd_hevc_optimisations.patch - patch -p1 < ../../0001-Squashed-commit-of-the-following.patch -+patch -p1 < ../../0001-avcodec-add-h264_mvc-codec-id-and-profiles.patch -+patch -p1 < ../../0001-h264_parser-add-support-for-parsing-h264-mvc-NALUs.patch -+patch -p1 < ../../h264_parser_fix_parsing_of_mvc_slices_in_some_corner_cases.patch +@@ -132,6 +132,9 @@ patch -p1 < ../hevcdsp_ARM_NEON_optimized_epel_functions.patch + patch -p1 < ../added_ARM_NEON_optimized_SAO_patches.patch + patch -p1 < ../pfcd_hevc_optimisations.patch + patch -p1 < ../0001-Squashed-commit-of-the-following.patch ++patch -p1 < ../0001-avcodec-add-h264_mvc-codec-id-and-profiles.patch ++patch -p1 < ../0001-h264_parser-add-support-for-parsing-h264-mvc-NALUs.patch ++patch -p1 < ../h264_parser_fix_parsing_of_mvc_slices_in_some_corner_cases.patch CFLAGS="$CFLAGS" CXXFLAGS="$CXXFLAGS" LDFLAGS="$LDFLAGS" \ ./configure --prefix=$FFMPEG_PREFIX \ @@ -52335,10 +47868,10 @@ index 0000000000000000000000000000000000000000..b39480ad098b9cd0882fcf75b96afb1b +2.7.4 + -From c2b0929d428aa4eb33d771121448a59e883c9842 Mon Sep 17 00:00:00 2001 +From 56c71f3a8e771ca8c61c4111b8622614f0f41bdb Mon Sep 17 00:00:00 2001 From: Anton Fedchin Date: Wed, 20 Jan 2016 17:02:16 +0300 -Subject: [PATCH 40/67] [VideoPlayer] DemuxFFmpeg: Properly demuxing h264_mvc +Subject: [PATCH 38/61] [VideoPlayer] DemuxFFmpeg: Properly demuxing h264_mvc streams. --- @@ -52346,7 +47879,7 @@ Subject: [PATCH 40/67] [VideoPlayer] DemuxFFmpeg: Properly demuxing h264_mvc 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -index 84310bbda6440dd10f9aa0711859f4dc0bb1fd1a..16e8e270b5a060bd174f794480a8b178a620d490 100644 +index c8ba4f869e844550e47ab9084aad1c59ba10f53a..1388a08c0403b0ab8942d4851ab97a229a9a777a 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp @@ -25,6 +25,7 @@ @@ -52357,7 +47890,7 @@ index 84310bbda6440dd10f9aa0711859f4dc0bb1fd1a..16e8e270b5a060bd174f794480a8b178 #include "DVDClock.h" // for DVD_TIME_BASE #include "DVDDemuxUtils.h" #include "DVDInputStreams/DVDInputStream.h" -@@ -1249,6 +1250,15 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) +@@ -1262,6 +1263,15 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) } case AVMEDIA_TYPE_VIDEO: { @@ -52373,7 +47906,7 @@ index 84310bbda6440dd10f9aa0711859f4dc0bb1fd1a..16e8e270b5a060bd174f794480a8b178 CDemuxStreamVideoFFmpeg* st = new CDemuxStreamVideoFFmpeg(this, pStream); stream = st; if(strcmp(m_pFormatContext->iformat->name, "flv") == 0) -@@ -1257,7 +1267,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) +@@ -1270,7 +1280,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) st->bVFR = false; // never trust pts in avi files with h264. @@ -52382,7 +47915,7 @@ index 84310bbda6440dd10f9aa0711859f4dc0bb1fd1a..16e8e270b5a060bd174f794480a8b178 st->bPTSInvalid = true; #if defined(AVFORMAT_HAS_STREAM_GET_R_FRAME_RATE) -@@ -1328,6 +1338,17 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) +@@ -1341,6 +1351,17 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) if (av_dict_get(pStream->metadata, "title", NULL, 0)) st->m_description = av_dict_get(pStream->metadata, "title", NULL, 0)->value; @@ -52401,10 +47934,10 @@ index 84310bbda6440dd10f9aa0711859f4dc0bb1fd1a..16e8e270b5a060bd174f794480a8b178 } case AVMEDIA_TYPE_DATA: -From 052ba44b0a0bd4736bc330c2f86e34cb8424ba60 Mon Sep 17 00:00:00 2001 +From 1cf1661ac0d3a7a9a8c29e695370f5f4b038cd9f Mon Sep 17 00:00:00 2001 From: Anton Fedchin Date: Thu, 25 Feb 2016 11:21:25 +0300 -Subject: [PATCH 41/67] [Stereo3D] Added mvc modes. +Subject: [PATCH 39/61] [Stereo3D] Added mvc modes. --- xbmc/cores/VideoPlayer/VideoRenderers/RenderFlags.cpp | 4 ++++ @@ -52458,17 +47991,17 @@ index 1443acaf0f25df458ae49766e13dd0323454f2eb..6eb0752994bc5f8c47efbbf211120af0 i++; } -From 0bcb7f56f0fa79c4d7af4c64e0b931a997045d72 Mon Sep 17 00:00:00 2001 +From f64eab2d4da72fcf95e002dc26f3139e9550f690 Mon Sep 17 00:00:00 2001 From: Anton Fedchin Date: Sat, 23 Jan 2016 10:21:32 +0300 -Subject: [PATCH 42/67] [VideoPlayer] Fix possible wrong aspect. +Subject: [PATCH 40/61] [VideoPlayer] Fix possible wrong aspect. --- xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp b/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp -index f6d1b8572c6a4a8b4a193ebfc9d36d85ccd2d819..6b97183835ce7d614e8814cb065ac168947f5ce1 100644 +index 11ffffb23b435b1ea77fc756cf321013393f9f4a..63454775e1b8460afc2df1ab93633ec49156efd3 100644 --- a/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp +++ b/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp @@ -182,7 +182,7 @@ void CVideoPlayerVideo::OpenStream(CDVDStreamInfo &hint, CDVDVideoCodec* codec) @@ -52481,14 +48014,14 @@ index f6d1b8572c6a4a8b4a193ebfc9d36d85ccd2d819..6b97183835ce7d614e8814cb065ac168 else m_fForcedAspectRatio = 0.0; -From b409948c86ffdb3b000a82333be9c4ddeb45ddd7 Mon Sep 17 00:00:00 2001 +From e0dbe5d847499befef2382ee01f7f13438e4356e Mon Sep 17 00:00:00 2001 From: Anton Fedchin Date: Fri, 22 Jan 2016 18:18:33 +0300 -Subject: [PATCH 43/67] [VideoPlayer] DemuxFFmpeg: ssif remux +Subject: [PATCH 41/61] [VideoPlayer] DemuxFFmpeg: ssif remux --- project/VS2010Express/XBMC.vcxproj | 2 + - project/VS2010Express/XBMC.vcxproj.filters | 8 +- + project/VS2010Express/XBMC.vcxproj.filters | 6 + xbmc/cores/VideoPlayer/DVDDemuxers/CMakeLists.txt | 2 + .../VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp | 47 ++++++- .../cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.h | 2 + @@ -52496,15 +48029,15 @@ Subject: [PATCH 43/67] [VideoPlayer] DemuxFFmpeg: ssif remux .../VideoPlayer/DVDDemuxers/DVDDemuxStreamSSIF.h | 49 +++++++ xbmc/cores/VideoPlayer/DVDDemuxers/Makefile.in | 1 + xbmc/settings/AdvancedSettings.cpp | 2 +- - 9 files changed, 260 insertions(+), 9 deletions(-) + 9 files changed, 259 insertions(+), 8 deletions(-) create mode 100644 xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxStreamSSIF.cpp create mode 100644 xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxStreamSSIF.h diff --git a/project/VS2010Express/XBMC.vcxproj b/project/VS2010Express/XBMC.vcxproj -index 164b608f77e4848bda558daf44dede1fc18a8fb4..601c5848ab9bda32e90fced986cf61dad38800bf 100644 +index fc546b1efa6a8daf521a3bc44da62782603be5d8..1b5c0643fe18f61df6829a4eb33c9a82fd8468a4 100644 --- a/project/VS2010Express/XBMC.vcxproj +++ b/project/VS2010Express/XBMC.vcxproj -@@ -295,6 +295,7 @@ copy "..\Win32BuildSetup\dependencies\python27.dll" "$(TargetDir)" +@@ -296,6 +296,7 @@ copy "..\Win32BuildSetup\dependencies\python27.dll" "$(TargetDir)" @@ -52512,7 +48045,7 @@ index 164b608f77e4848bda558daf44dede1fc18a8fb4..601c5848ab9bda32e90fced986cf61da -@@ -1069,6 +1070,7 @@ copy "..\Win32BuildSetup\dependencies\python27.dll" "$(TargetDir)" +@@ -1072,6 +1073,7 @@ copy "..\Win32BuildSetup\dependencies\python27.dll" "$(TargetDir)" @@ -52521,10 +48054,10 @@ index 164b608f77e4848bda558daf44dede1fc18a8fb4..601c5848ab9bda32e90fced986cf61da diff --git a/project/VS2010Express/XBMC.vcxproj.filters b/project/VS2010Express/XBMC.vcxproj.filters -index b3c53788819764a400ea53e12440ba229735819c..b2d5230fdcd32f6db50e580f55cd7a63d4d19247 100644 +index ef911b1ce3b7d00674c332078584485de2dc49ae..0524f95c8549be034a3592b2c1909d688f0c9b17 100644 --- a/project/VS2010Express/XBMC.vcxproj.filters +++ b/project/VS2010Express/XBMC.vcxproj.filters -@@ -3452,6 +3452,9 @@ +@@ -3455,6 +3455,9 @@ dialogs @@ -52533,26 +48066,19 @@ index b3c53788819764a400ea53e12440ba229735819c..b2d5230fdcd32f6db50e580f55cd7a63 + - -@@ -6704,6 +6707,9 @@ - - cores\AudioEngine\Engines\ActiveAE\AudioDSPAddons + +@@ -6722,6 +6725,9 @@ + + cores\AudioEngine\Engines\ActiveAE + + cores\VideoPlayer\DVDDemuxers + - -@@ -6790,4 +6796,4 @@ - shaders - - -- -\ No newline at end of file -+ + diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/CMakeLists.txt b/xbmc/cores/VideoPlayer/DVDDemuxers/CMakeLists.txt -index 7d254f7650377485b909f26189d126455d49569a..65b369054c4ea329649a51f20f448394c70b110d 100644 +index 63776b1333bb66483303e44d6ebe60f3cd7e14d7..0da129ff99f57dc38ca8a854854d9fe658651e1f 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/CMakeLists.txt +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/CMakeLists.txt @@ -5,6 +5,7 @@ set(SOURCES DemuxMultiSource.cpp @@ -52572,7 +48098,7 @@ index 7d254f7650377485b909f26189d126455d49569a..65b369054c4ea329649a51f20f448394 DVDDemuxUtils.h DVDDemuxVobsub.h diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -index 16e8e270b5a060bd174f794480a8b178a620d490..4490b16318e1c54822cdbbf5fa6344d66c2fdbdd 100644 +index 1388a08c0403b0ab8942d4851ab97a229a9a777a..5775a82c37768bc585645ff5a8eb259c07ef9f9c 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp @@ -164,6 +164,7 @@ CDVDDemuxFFmpeg::CDVDDemuxFFmpeg() : CDVDDemux() @@ -52650,7 +48176,7 @@ index 16e8e270b5a060bd174f794480a8b178a620d490..4490b16318e1c54822cdbbf5fa6344d6 if (!stream) { CLog::Log(LOGERROR, "CDVDDemuxFFmpeg::AddStream - internal error, stream is null"); -@@ -1018,6 +1040,9 @@ bool CDVDDemuxFFmpeg::SeekTime(int time, bool backwords, double *startpts) +@@ -1023,6 +1045,9 @@ bool CDVDDemuxFFmpeg::SeekTime(int time, bool backwords, double *startpts) m_pkt.result = -1; av_packet_unref(&m_pkt.pkt); @@ -52660,7 +48186,7 @@ index 16e8e270b5a060bd174f794480a8b178a620d490..4490b16318e1c54822cdbbf5fa6344d6 CDVDInputStream::IPosTime* ist = m_pInput->GetIPosTime(); if (ist) { -@@ -1085,6 +1110,9 @@ bool CDVDDemuxFFmpeg::SeekByte(int64_t pos) +@@ -1098,6 +1123,9 @@ bool CDVDDemuxFFmpeg::SeekByte(int64_t pos) m_pkt.result = -1; av_packet_unref(&m_pkt.pkt); @@ -52670,7 +48196,7 @@ index 16e8e270b5a060bd174f794480a8b178a620d490..4490b16318e1c54822cdbbf5fa6344d6 return (ret >= 0); } -@@ -1252,11 +1280,12 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) +@@ -1265,11 +1293,12 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) { if (pStream->codec->codec_id == AV_CODEC_ID_H264_MVC) { @@ -52686,7 +48212,7 @@ index 16e8e270b5a060bd174f794480a8b178a620d490..4490b16318e1c54822cdbbf5fa6344d6 break; } CDemuxStreamVideoFFmpeg* st = new CDemuxStreamVideoFFmpeg(this, pStream); -@@ -1342,7 +1371,11 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) +@@ -1355,7 +1384,11 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) { if (CDVDCodecUtils::IsH264AnnexB(m_pFormatContext->iformat->name, pStream)) { @@ -52699,7 +48225,7 @@ index 16e8e270b5a060bd174f794480a8b178a620d490..4490b16318e1c54822cdbbf5fa6344d6 } else if (CDVDCodecUtils::ProcessH264MVCExtradata(pStream->codec->extradata, pStream->codec->extradata_size)) { -@@ -1435,7 +1468,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) +@@ -1448,7 +1481,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) if (langTag) strncpy(stream->language, langTag->value, 3); @@ -52958,10 +48484,10 @@ index e4f8aed0af96fe0dceec4d8517087742f2c7df81..f3b717ddabb4729fe0db5ebab5a7913b LIB = DVDDemuxers.a diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp -index ae21da29314ae8faa35129a79e62e82b55fbc306..8426b6c3f8f6af274e2990c8da323e4064db9b65 100644 +index 60e5652f69e96a559d8080e01dc214a56fb19343..cdaf53585a89a0da3a4038178806ee937049fe42 100644 --- a/xbmc/settings/AdvancedSettings.cpp +++ b/xbmc/settings/AdvancedSettings.cpp -@@ -392,7 +392,7 @@ void CAdvancedSettings::Initialize() +@@ -391,7 +391,7 @@ void CAdvancedSettings::Initialize() m_pictureExtensions = ".png|.jpg|.jpeg|.bmp|.gif|.ico|.tif|.tiff|.tga|.pcx|.cbz|.zip|.cbr|.rar|.rss|.webp|.jp2|.apng"; m_musicExtensions = ".nsv|.m4a|.flac|.aac|.strm|.pls|.rm|.rma|.mpa|.wav|.wma|.ogg|.mp3|.mp2|.m3u|.gdm|.imf|.m15|.sfx|.uni|.ac3|.dts|.cue|.aif|.aiff|.wpl|.ape|.mac|.mpc|.mp+|.mpp|.shn|.zip|.rar|.wv|.dsp|.xsp|.xwav|.waa|.wvs|.wam|.gcm|.idsp|.mpdsp|.mss|.spt|.rsd|.sap|.cmc|.cmr|.dmc|.mpt|.mpd|.rmt|.tmc|.tm8|.tm2|.oga|.url|.pxml|.tta|.rss|.wtv|.mka|.tak|.opus|.dff|.dsf"; @@ -52971,47 +48497,33 @@ index ae21da29314ae8faa35129a79e62e82b55fbc306..8426b6c3f8f6af274e2990c8da323e40 m_discStubExtensions = ".disc"; // internal music extensions -From ac2167deb4a7e8408903ca2aab446b3d0d954fa7 Mon Sep 17 00:00:00 2001 +From e2b43c6da9e7cdaba0c6f7d7bd59b36f3b6dc32f Mon Sep 17 00:00:00 2001 From: Anton Fedchin Date: Tue, 23 Feb 2016 16:01:08 +0300 -Subject: [PATCH 44/67] [libbluray] bump libbluray to 0.9.2-mvc. +Subject: [PATCH 42/61] [libbluray] bump libbluray to 0.9.2-mvc. --- project/BuildDependencies/scripts/0_package.list | 2 +- - xbmc/DllPaths_win32.h | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) + 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/BuildDependencies/scripts/0_package.list b/project/BuildDependencies/scripts/0_package.list -index 71024bfb7da48ddb033b159f83037319176229b4..2565d1d08f6591955266fcca3f1a8031db4379e4 100644 +index 2b6840102cdcaa464428694d16ac8d58e7c2d03f..4f3bddf0ef2e985986efffb97b9aeae5fa36d3e1 100644 --- a/project/BuildDependencies/scripts/0_package.list +++ b/project/BuildDependencies/scripts/0_package.list -@@ -16,7 +16,7 @@ freetype-2.4.6-win32-3.7z +@@ -17,7 +17,7 @@ freetype-2.6.3-win32-vc140.7z giflib-5.1.4-win32-vc140.7z jsonschemabuilder-1.0.0-win32-3.7z - libass-0.12.1-win32.7z --libbluray-0.8.1-win32-vc120.7z + libass-0.13.2-win32-vc140.7z +-libbluray-0.9.3-win32-vc140.7z +libbluray-0.9.2-mvc-win32-vc120.7z - libcdio-0.83-win32-2.7z - libcec-3.0.0-win32-2.7z - libexpat_2.0.1-win32.7z -diff --git a/xbmc/DllPaths_win32.h b/xbmc/DllPaths_win32.h -index 3748589f39b1f83f1e23e9eb4f64eddcf61cb030..ff34ff541049ad7d2fa5472c49e6412e0d68056b 100644 ---- a/xbmc/DllPaths_win32.h -+++ b/xbmc/DllPaths_win32.h -@@ -35,7 +35,7 @@ - #define DLL_PATH_LIBDVDNAV "special://xbmcbin/system/players/VideoPlayer/libdvdnav.dll" - - /* libbluray */ --#define DLL_PATH_LIBBLURAY "special://xbmcbin/system/players/dvdplayer/libbluray.dll" -+#define DLL_PATH_LIBBLURAY "special://xbmcbin/system/players/VideoPlayer/libbluray.dll" - - #endif - + libcdio-0.9.3-win32-vc140.7z + libcec-3.1.0-win32-vc140.7z + libfribidi-0.19.2-win32.7z -From 6bb5fcf3d003296bbe290c171577bb65ba6ea04d Mon Sep 17 00:00:00 2001 +From 25d2b378d13a6472ff7fe16dd98289b75cac352e Mon Sep 17 00:00:00 2001 From: Anton Fedchin Date: Tue, 23 Feb 2016 16:02:46 +0300 -Subject: [PATCH 45/67] [3DBD] Added support of 3D-BluRay playback. +Subject: [PATCH 43/61] [3DBD] Added support of 3D-BluRay playback. --- lib/DllLibbluray.h | 8 + @@ -53071,10 +48583,10 @@ index f5a337fe19beff472557c97ff7a203ad30a912b2..03f93391265e164837c2a17a8fe6d7da public: diff --git a/project/VS2010Express/XBMC.vcxproj b/project/VS2010Express/XBMC.vcxproj -index 601c5848ab9bda32e90fced986cf61dad38800bf..189b698f57d1e2bbb50dd7541136309c59a1fb84 100644 +index 1b5c0643fe18f61df6829a4eb33c9a82fd8468a4..fdb0abb808fed44ec3d7896289defe94ee9d52b1 100644 --- a/project/VS2010Express/XBMC.vcxproj +++ b/project/VS2010Express/XBMC.vcxproj -@@ -295,6 +295,7 @@ copy "..\Win32BuildSetup\dependencies\python27.dll" "$(TargetDir)" +@@ -296,6 +296,7 @@ copy "..\Win32BuildSetup\dependencies\python27.dll" "$(TargetDir)" @@ -53082,7 +48594,7 @@ index 601c5848ab9bda32e90fced986cf61dad38800bf..189b698f57d1e2bbb50dd7541136309c -@@ -1070,6 +1071,7 @@ copy "..\Win32BuildSetup\dependencies\python27.dll" "$(TargetDir)" +@@ -1073,6 +1074,7 @@ copy "..\Win32BuildSetup\dependencies\python27.dll" "$(TargetDir)" @@ -53091,10 +48603,10 @@ index 601c5848ab9bda32e90fced986cf61dad38800bf..189b698f57d1e2bbb50dd7541136309c diff --git a/project/VS2010Express/XBMC.vcxproj.filters b/project/VS2010Express/XBMC.vcxproj.filters -index b2d5230fdcd32f6db50e580f55cd7a63d4d19247..65d8e075716c05669c1e5665de9e3ba0ac1188ea 100644 +index 0524f95c8549be034a3592b2c1909d688f0c9b17..049aa3e93113bbaaa144dc9292be7832e8f5f696 100644 --- a/project/VS2010Express/XBMC.vcxproj.filters +++ b/project/VS2010Express/XBMC.vcxproj.filters -@@ -3455,6 +3455,9 @@ +@@ -3458,6 +3458,9 @@ cores\VideoPlayer\DVDDemuxers @@ -53103,8 +48615,8 @@ index b2d5230fdcd32f6db50e580f55cd7a63d4d19247..65d8e075716c05669c1e5665de9e3ba0 + - -@@ -6710,6 +6713,9 @@ + +@@ -6728,6 +6731,9 @@ cores\VideoPlayer\DVDDemuxers @@ -53113,9 +48625,9 @@ index b2d5230fdcd32f6db50e580f55cd7a63d4d19247..65d8e075716c05669c1e5665de9e3ba0 + - + diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/CMakeLists.txt b/xbmc/cores/VideoPlayer/DVDDemuxers/CMakeLists.txt -index 65b369054c4ea329649a51f20f448394c70b110d..2706bcadc177a4f8f9c12c3be7976f7a0f81fc8f 100644 +index 0da129ff99f57dc38ca8a854854d9fe658651e1f..82d4b499245afda1a51ca281584cc47fc76173d1 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/CMakeLists.txt +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/CMakeLists.txt @@ -5,6 +5,7 @@ set(SOURCES DemuxMultiSource.cpp @@ -53135,7 +48647,7 @@ index 65b369054c4ea329649a51f20f448394c70b110d..2706bcadc177a4f8f9c12c3be7976f7a DVDDemuxPacket.h DVDDemuxUtils.h diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -index 4490b16318e1c54822cdbbf5fa6344d66c2fdbdd..54e4d0b66680a08c1e4c1be343fabe4371aec6af 100644 +index 5775a82c37768bc585645ff5a8eb259c07ef9f9c..65d998f65493c1b463a4d1cabf36a16c9a06d498 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp @@ -27,6 +27,7 @@ @@ -53196,7 +48708,7 @@ index 4490b16318e1c54822cdbbf5fa6344d66c2fdbdd..54e4d0b66680a08c1e4c1be343fabe43 if (stream->type == STREAM_DATA && stream->codec == AV_CODEC_ID_H264_MVC && pPacket->iSize) stream = GetStream(pPacket->iStreamId); } -@@ -1375,6 +1380,29 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) +@@ -1388,6 +1393,29 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) { m_pSSIF->SetH264StreamId(streamIdx); pStream->codec->codec_tag = MKTAG('A', 'M', 'V', 'C'); @@ -53226,7 +48738,7 @@ index 4490b16318e1c54822cdbbf5fa6344d66c2fdbdd..54e4d0b66680a08c1e4c1be343fabe43 } } else if (CDVDCodecUtils::ProcessH264MVCExtradata(pStream->codec->extradata, pStream->codec->extradata_size)) -@@ -1635,6 +1663,12 @@ bool CDVDDemuxFFmpeg::SeekChapter(int chapter, double* startpts) +@@ -1648,6 +1676,12 @@ bool CDVDDemuxFFmpeg::SeekChapter(int chapter, double* startpts) } Flush(); @@ -53239,7 +48751,7 @@ index 4490b16318e1c54822cdbbf5fa6344d66c2fdbdd..54e4d0b66680a08c1e4c1be343fabe43 return true; } -@@ -1704,6 +1738,11 @@ std::string CDVDDemuxFFmpeg::GetStreamCodecName(int iStreamId) +@@ -1717,6 +1751,11 @@ std::string CDVDDemuxFFmpeg::GetStreamCodecName(int iStreamId) bool CDVDDemuxFFmpeg::IsProgramChange() { @@ -54056,10 +49568,10 @@ index b967a85e6557e42a7f1235cdd804d5a0263b866f..561fb5cd4f971bc9ee4f41218a60bb3d typedef std::shared_ptr SOverlay; typedef std::list SOverlays; -From 9209fd1862041094e9f01e17c377c6d50c37ebb0 Mon Sep 17 00:00:00 2001 +From fab0e4608dd6560b9c001eb1189cd000e90439f9 Mon Sep 17 00:00:00 2001 From: Anton Fedchin Date: Wed, 2 Mar 2016 23:31:50 +0300 -Subject: [PATCH 46/67] [BaseRenderer] Fix aspect for TAB/SBS (need more +Subject: [PATCH 44/61] [BaseRenderer] Fix aspect for TAB/SBS (need more testing) --- @@ -54103,94 +49615,41 @@ index f18c671d90c85eed1ca4bd52028d7e5074a1312a..5c6f7453c2b3fd1155c18af8d37cb3d4 void CBaseRenderer::ManageRenderArea() -From 7aa4746fe6adef77e5ff99b60d242a575fff583c Mon Sep 17 00:00:00 2001 +From 4e661a9b6bafbcfcafdcc33acdbebaa778c947f7 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 29 Feb 2016 17:00:50 +0000 -Subject: [PATCH 47/67] libbluray: Bump to Nevcairie's v0.9.2 +Subject: [PATCH 45/61] libbluray: Bump to Nevcairie's v0.9.2 This includes 3D support --- - tools/depends/target/libbluray/Makefile | 1 + - .../libbluray/bump_to_Nevcairie_v0.9.2.patch | 24397 +++++++++++++++++++ - 2 files changed, 24398 insertions(+) + tools/depends/target/libbluray/Makefile | 1 + + .../libbluray/bump_to_Nevcairie_v0.9.2.patch | 1629 ++++++++++++++++++++ + 2 files changed, 1630 insertions(+) create mode 100644 tools/depends/target/libbluray/bump_to_Nevcairie_v0.9.2.patch diff --git a/tools/depends/target/libbluray/Makefile b/tools/depends/target/libbluray/Makefile -index 3c85b96ca38409fec6de87cb30162b725ce170db..d8fa16ed83ea997c8b3cf34ee83383e830986197 100644 +index 09d2a8e04ef4ef694f3d7a6152ab9be0e294ce2f..741a820df47fd8014192f6c0c546abb72d33ab1f 100644 --- a/tools/depends/target/libbluray/Makefile +++ b/tools/depends/target/libbluray/Makefile -@@ -27,6 +27,7 @@ $(PLATFORM): $(TARBALLS_LOCATION)/$(ARCHIVE) $(DEPS) - ifeq ($(OS),android) - cd $(PLATFORM); patch -p1 < ../android.patch - endif +@@ -24,6 +24,7 @@ $(PLATFORM): $(TARBALLS_LOCATION)/$(ARCHIVE) $(DEPS) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + # libbluray has borked Makefile.am with respect to CFLAGS, remove the offending line + sed -i -e "s|CFLAGS=|#CFLAGS=|" $(PLATFORM)/Makefile.am + cd $(PLATFORM); patch -p1 < ../bump_to_Nevcairie_v0.9.2.patch cd $(PLATFORM); ./bootstrap cd $(PLATFORM); $(CONFIGURE) diff --git a/tools/depends/target/libbluray/bump_to_Nevcairie_v0.9.2.patch b/tools/depends/target/libbluray/bump_to_Nevcairie_v0.9.2.patch new file mode 100644 -index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed41072c65354a +index 0000000000000000000000000000000000000000..5ef0124e35c9d81143921a328e272220640fb84e --- /dev/null +++ b/tools/depends/target/libbluray/bump_to_Nevcairie_v0.9.2.patch -@@ -0,0 +1,24397 @@ -+diff --git a/ChangeLog b/ChangeLog -+index ffc7788..545fb3f 100644 -+--- a/ChangeLog -++++ b/ChangeLog -+@@ -1,3 +1,29 @@ -++2015-12-01: Version 0.9.2 -++- Add primary audio stream to bd_select_stream(). -++- Improve error resilience. -++- Fix Java 8 compability issues. -++- Fix Android build. -++- Fix SecurityException in AWTAutoShutdown. -++- Fix BD-J check when install path in Windows contains non-ASCII chars. -++- Fix jvm.dll loading in Windows ($JAVA_HOME/bin should be in dll load path). -++- Fix class translating in recent Java 8 versions. -++ -++2015-11-03: Version 0.9.1 -++- Improved BD-J security. -++- Improved error resilience. -++- Improved seeking (avoid skipping PAT/PMT/PCR). -++- Fix UO mask check when bd_play_title() is used for Top Menu. -++- Fix re-starting of title bound Xlets when title changes. -++- Fix loading classes with invalid debug info. -++ -++2015-10-02: Version 0.9.0 -++- Add functions to read files from VFS. -++- Improved error resilience. -++- Improved BD-J compability. -++- Fix Xlet-initiated font caching. -++- Fix return value when setting BLURAY_PLAYER_SETTING_DECODE_PG. -++- Fix build with C++ compiler -++ -+ 2015-05-15: Version 0.8.1 -+ - Notify application when UO mask changes. -+ - Improved error resilience. +@@ -0,0 +1,1629 @@ +diff --git a/Makefile.am b/Makefile.am -+index e03e926..87093c4 100644 ++index 3a54bfc..035553b 100644 +--- a/Makefile.am ++++ b/Makefile.am -+@@ -26,7 +26,8 @@ EXTRA_DIST = \ -+ src/libbluray/bdj/build.xml \ -+ src/libbluray/bdj/java \ -+ src/libbluray/bdj/java-j2me \ -+- src/libbluray/bdj/java-j2se -++ src/libbluray/bdj/java-j2se \ -++ contrib/asm -+ -+ lib_LTLIBRARIES=libbluray.la -+ libbluray_la_SOURCES = \ -+@@ -149,7 +150,7 @@ libbluray_la_SOURCES+= \ -+ endif -+ endif -+ -+-libbluray_la_LDFLAGS= -version-info $(LT_VERSION_INFO) -export-symbols-regex "^bd_" -++libbluray_la_LDFLAGS= -no-undefined -version-info $(LT_VERSION_INFO) -export-symbols-regex "^bd_" -+ libbluray_la_LIBADD= $(LIBXML2_LIBS) $(FT2_LIBS) $(FONTCONFIG_LIBS) -+ -+ noinst_HEADERS = \ -+@@ -158,6 +159,15 @@ noinst_HEADERS = \ ++@@ -161,6 +161,15 @@ noinst_HEADERS = \ + jni/win32/jni_md.h \ + jni/darwin/jni_md.h + @@ -54206,7 +49665,7 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + pkginclude_HEADERS = \ + src/file/filesystem.h \ + src/libbluray/bluray.h \ -+@@ -165,6 +175,9 @@ pkginclude_HEADERS = \ ++@@ -168,6 +177,9 @@ pkginclude_HEADERS = \ + src/libbluray/keys.h \ + src/libbluray/player_settings.h \ + src/libbluray/bdnav/clpi_data.h \ @@ -54216,94 +49675,6 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + src/libbluray/bdnav/meta_data.h \ + src/libbluray/decoders/overlay.h \ + src/util/log_control.h -+@@ -185,10 +198,12 @@ endif -+ -+ -+ if USING_BDJAVA -++if USING_BDJAVA_BUILD_JAR -+ jardir=$(datadir)/java/ -+ jar_DATA=$(top_builddir)/.libs/libbluray-$(BDJ_TYPE)-$(VERSION).jar -+ -+ $(top_builddir)/.libs/libbluray-$(BDJ_TYPE)-$(VERSION).jar: all-local -++endif -+ -+ libbluray_la_SOURCES += \ -+ src/libbluray/bdj/bdj.h \ -+@@ -213,6 +228,7 @@ libbluray_la_SOURCES += \ -+ -+ AM_CFLAGS += $(BDJAVA_CFLAGS) -+ -++if USING_BDJAVA_BUILD_JAR -+ all-local: -+ ant -f $(top_srcdir)/src/libbluray/bdj/build.xml \ -+ -Dbuild='$(abs_builddir)/src/libbluray/bdj/build' \ -+@@ -228,6 +244,7 @@ clean-local: -+ -Dversion='$(BDJ_TYPE)-$(VERSION)' \ -+ clean -+ endif -++endif -+ -+ pkgconfigdir = $(libdir)/pkgconfig -+ pkgconfig_DATA = src/libbluray.pc -+@@ -265,20 +282,20 @@ bd_info_LDADD = libbluray.la -+ bdsplice_SOURCES = src/examples/bdsplice.c -+ bdsplice_LDADD = libbluray.la -+ -+-bdj_test_SOURCES = src/examples/bdj_test.c -++bdj_test_SOURCES = src/devtools/bdj_test.c -+ bdj_test_LDADD = libbluray.la -+ -+-bdjo_dump_SOURCES = src/examples/bdjo_dump.c -++bdjo_dump_SOURCES = src/devtools/bdjo_dump.c -+ bdjo_dump_LDADD = libbluray.la -+ -+ clpi_dump_CFLAGS = $(AM_CFLAGS) -+ clpi_dump_SOURCES = \ -+- src/examples/clpi_dump.c \ -+- src/examples/util.c \ -+- src/examples/util.h -++ src/devtools/clpi_dump.c \ -++ src/devtools/util.c \ -++ src/devtools/util.h -+ clpi_dump_LDADD = libbluray.la -+ -+-hdmv_test_SOURCES = src/examples/hdmv_test.c -++hdmv_test_SOURCES = src/devtools/hdmv_test.c -+ hdmv_test_LDADD = libbluray.la -+ -+ index_dump_SOURCES = src/examples/index_dump.c -+@@ -291,15 +308,15 @@ list_titles_SOURCES = src/examples/list_titles.c -+ list_titles_LDADD = libbluray.la -+ -+ mobj_dump_CFLAGS = $(AM_CFLAGS) -+-mobj_dump_SOURCES = src/examples/mobj_dump.c \ -++mobj_dump_SOURCES = src/devtools/mobj_dump.c \ -+ src/libbluray/hdmv/mobj_print.c -+ mobj_dump_LDADD = libbluray.la -+ -+ mpls_dump_CFLAGS = $(AM_CFLAGS) -+ mpls_dump_SOURCES = \ -+- src/examples/mpls_dump.c \ -+- src/examples/util.c \ -+- src/examples/util.h -++ src/devtools/mpls_dump.c \ -++ src/devtools/util.c \ -++ src/devtools/util.h -+ mpls_dump_LDADD = libbluray.la -+ -+ sound_dump_SOURCES = src/examples/sound_dump.c -+diff --git a/bootstrap b/bootstrap -+index 872167c..bde67cb 100755 -+--- a/bootstrap -++++ b/bootstrap -+@@ -1,3 +1,7 @@ -+ #!/bin/sh -+ -++set -e -++ -++cd "$(dirname "$0")" -++ -+ autoreconf -vif +diff --git a/config.h b/config.h +new file mode 100644 +index 0000000..6764704 @@ -54467,15024 +49838,6 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 ++ ++/* Define to '0x0502' for Windows XP SP2 APIs. */ ++#define _WIN32_WINNT 0x0502 -+diff --git a/configure.ac b/configure.ac -+index 5d5fe2c..ed08c96 100644 -+--- a/configure.ac -++++ b/configure.ac -+@@ -1,7 +1,7 @@ -+ dnl library version number -+ m4_define([bluray_major], 0) -+-m4_define([bluray_minor], 8) -+-m4_define([bluray_micro], 1) -++m4_define([bluray_minor], 9) -++m4_define([bluray_micro], 2) -+ m4_define([bluray_version],[bluray_major.bluray_minor.bluray_micro]) -+ -+ dnl shared library version (.so version) -+@@ -12,9 +12,9 @@ dnl - If interfaces have been changed or removed, increase current and set age a -+ dnl -+ dnl Library file name will be libbluray.so.(current-age).age.revision -+ dnl -+-m4_define([lt_current], 9) -+-m4_define([lt_revision], 1) -+-m4_define([lt_age], 8) -++m4_define([lt_current], 10) -++m4_define([lt_revision], 2) -++m4_define([lt_age], 9) -+ -+ dnl initilization -+ AC_INIT([libbluray], bluray_version, [http://www.videolan.org/developers/libbluray.html]) -+@@ -87,7 +87,15 @@ AC_ARG_ENABLE([bdjava], -+ [use_bdjava=yes]) -+ -+ AC_ARG_ENABLE([udf], -+- [AS_HELP_STRING([--enable-udf], [enable UDF support @<:@default=disabled@:>@])]) -++ [AS_HELP_STRING([--disable-udf], [disable UDF support @<:@default=enabled@:>@])], -++ [enable_udf=$enableval], -++ [enable_udf=yes]) -++ -++AC_ARG_ENABLE([bdjava-jar], -++ [AS_HELP_STRING([--disable-bdjava-jar], -++ [disable building of BD-Java JAR file @<:@default=enabled@:>@])], -++ [use_bdjava_jar=$enableval], -++ [use_bdjava_jar=yes]) -+ -+ AC_ARG_WITH([libxml2], -+ [AS_HELP_STRING([--without-libxml2], [build without libxml2 support @<:@default=with@:>@])]) -+@@ -224,7 +232,7 @@ if [[ $use_bdjava = "yes" ]]; then -+ ]) -+ -+ AC_CHECK_PROG(HAVE_ANT, [ant], yes, no) -+- if test "x$HAVE_ANT" = "xno"; then -++ if test "x$use_bdjava_jar" = "xyes" && test "x$HAVE_ANT" = "xno"; then -+ AC_MSG_ERROR([BD-J requires ANT, but ant was not found. Please install it.]) -+ fi -+ -+@@ -233,6 +241,7 @@ if [[ $use_bdjava = "yes" ]]; then -+ AC_DEFINE_UNQUOTED([JDK_HOME], ["$JDK_HOME"], [""]) -+ fi -+ AM_CONDITIONAL([USING_BDJAVA], [ test $use_bdjava = "yes" ]) -++AM_CONDITIONAL([USING_BDJAVA_BUILD_JAR], [ test $use_bdjava_jar = "yes" ]) -+ -+ dnl BD-J type -+ if test "$BDJ_TYPE" = "j2me"; then -+@@ -292,6 +301,7 @@ echo " --------" -+ echo " BD-J support: $use_bdjava" -+ if [[ $use_bdjava = "yes" ]]; then -+ echo " BD-J type: $BDJ_TYPE" -++echo " build JAR: $use_bdjava_jar" -+ if test x"$BDJ_BOOTCLASSPATH" != x""; then -+ echo " BD-J bootclasspath: $BDJ_BOOTCLASSPATH" -+ fi -+diff --git a/contrib/asm/LICENSE.txt b/contrib/asm/LICENSE.txt -+new file mode 100644 -+index 0000000..4d19185 -+--- /dev/null -++++ b/contrib/asm/LICENSE.txt -+@@ -0,0 +1,28 @@ -++ -++ ASM: a very small and fast Java bytecode manipulation framework -++ Copyright (c) 2000-2011 INRIA, France Telecom -++ All rights reserved. -++ -++ Redistribution and use in source and binary forms, with or without -++ modification, are permitted provided that the following conditions -++ are met: -++ 1. Redistributions of source code must retain the above copyright -++ notice, this list of conditions and the following disclaimer. -++ 2. Redistributions in binary form must reproduce the above copyright -++ notice, this list of conditions and the following disclaimer in the -++ documentation and/or other materials provided with the distribution. -++ 3. Neither the name of the copyright holders nor the names of its -++ contributors may be used to endorse or promote products derived from -++ this software without specific prior written permission. -++ -++ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ THE POSSIBILITY OF SUCH DAMAGE. -+diff --git a/contrib/asm/SOURCE b/contrib/asm/SOURCE -+new file mode 100644 -+index 0000000..804aede -+--- /dev/null -++++ b/contrib/asm/SOURCE -+@@ -0,0 +1,9 @@ -++Core functionality from asm 5.0.4 -++ -++http://asm.ow2.org/ -++ -++ASM is an all purpose Java bytecode manipulation and analysis framework. It can be used to modify -++existing classes or dynamically generate classes, directly in binary form. Provided common -++transformations and analysis algorithms allow to easily assemble custom complex transformations -++and code analysis tools. -++ -+diff --git a/contrib/asm/src/org/objectweb/asm/AnnotationVisitor.java b/contrib/asm/src/org/objectweb/asm/AnnotationVisitor.java -+new file mode 100644 -+index 0000000..b644083 -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/AnnotationVisitor.java -+@@ -0,0 +1,169 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * A visitor to visit a Java annotation. The methods of this class must be -++ * called in the following order: ( visit | visitEnum | -++ * visitAnnotation | visitArray )* visitEnd. -++ * -++ * @author Eric Bruneton -++ * @author Eugene Kuleshov -++ */ -++public abstract class AnnotationVisitor { -++ -++ /** -++ * The ASM API version implemented by this visitor. The value of this field -++ * must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -++ */ -++ protected final int api; -++ -++ /** -++ * The annotation visitor to which this visitor must delegate method calls. -++ * May be null. -++ */ -++ protected AnnotationVisitor av; -++ -++ /** -++ * Constructs a new {@link AnnotationVisitor}. -++ * -++ * @param api -++ * the ASM API version implemented by this visitor. Must be one -++ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -++ */ -++ public AnnotationVisitor(final int api) { -++ this(api, null); -++ } -++ -++ /** -++ * Constructs a new {@link AnnotationVisitor}. -++ * -++ * @param api -++ * the ASM API version implemented by this visitor. Must be one -++ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -++ * @param av -++ * the annotation visitor to which this visitor must delegate -++ * method calls. May be null. -++ */ -++ public AnnotationVisitor(final int api, final AnnotationVisitor av) { -++ if (api != Opcodes.ASM4 && api != Opcodes.ASM5) { -++ throw new IllegalArgumentException(); -++ } -++ this.api = api; -++ this.av = av; -++ } -++ -++ /** -++ * Visits a primitive value of the annotation. -++ * -++ * @param name -++ * the value name. -++ * @param value -++ * the actual value, whose type must be {@link Byte}, -++ * {@link Boolean}, {@link Character}, {@link Short}, -++ * {@link Integer} , {@link Long}, {@link Float}, {@link Double}, -++ * {@link String} or {@link Type} or OBJECT or ARRAY sort. This -++ * value can also be an array of byte, boolean, short, char, int, -++ * long, float or double values (this is equivalent to using -++ * {@link #visitArray visitArray} and visiting each array element -++ * in turn, but is more convenient). -++ */ -++ public void visit(String name, Object value) { -++ if (av != null) { -++ av.visit(name, value); -++ } -++ } -++ -++ /** -++ * Visits an enumeration value of the annotation. -++ * -++ * @param name -++ * the value name. -++ * @param desc -++ * the class descriptor of the enumeration class. -++ * @param value -++ * the actual enumeration value. -++ */ -++ public void visitEnum(String name, String desc, String value) { -++ if (av != null) { -++ av.visitEnum(name, desc, value); -++ } -++ } -++ -++ /** -++ * Visits a nested annotation value of the annotation. -++ * -++ * @param name -++ * the value name. -++ * @param desc -++ * the class descriptor of the nested annotation class. -++ * @return a visitor to visit the actual nested annotation value, or -++ * null if this visitor is not interested in visiting this -++ * nested annotation. The nested annotation value must be fully -++ * visited before calling other methods on this annotation -++ * visitor. -++ */ -++ public AnnotationVisitor visitAnnotation(String name, String desc) { -++ if (av != null) { -++ return av.visitAnnotation(name, desc); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits an array value of the annotation. Note that arrays of primitive -++ * types (such as byte, boolean, short, char, int, long, float or double) -++ * can be passed as value to {@link #visit visit}. This is what -++ * {@link ClassReader} does. -++ * -++ * @param name -++ * the value name. -++ * @return a visitor to visit the actual array value elements, or -++ * null if this visitor is not interested in visiting these -++ * values. The 'name' parameters passed to the methods of this -++ * visitor are ignored. All the array values must be visited -++ * before calling other methods on this annotation visitor. -++ */ -++ public AnnotationVisitor visitArray(String name) { -++ if (av != null) { -++ return av.visitArray(name); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits the end of the annotation. -++ */ -++ public void visitEnd() { -++ if (av != null) { -++ av.visitEnd(); -++ } -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/AnnotationWriter.java b/contrib/asm/src/org/objectweb/asm/AnnotationWriter.java -+new file mode 100644 -+index 0000000..6b95608 -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/AnnotationWriter.java -+@@ -0,0 +1,371 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * An {@link AnnotationVisitor} that generates annotations in bytecode form. -++ * -++ * @author Eric Bruneton -++ * @author Eugene Kuleshov -++ */ -++final class AnnotationWriter extends AnnotationVisitor { -++ -++ /** -++ * The class writer to which this annotation must be added. -++ */ -++ private final ClassWriter cw; -++ -++ /** -++ * The number of values in this annotation. -++ */ -++ private int size; -++ -++ /** -++ * true if values are named, false otherwise. Annotation -++ * writers used for annotation default and annotation arrays use unnamed -++ * values. -++ */ -++ private final boolean named; -++ -++ /** -++ * The annotation values in bytecode form. This byte vector only contains -++ * the values themselves, i.e. the number of values must be stored as a -++ * unsigned short just before these bytes. -++ */ -++ private final ByteVector bv; -++ -++ /** -++ * The byte vector to be used to store the number of values of this -++ * annotation. See {@link #bv}. -++ */ -++ private final ByteVector parent; -++ -++ /** -++ * Where the number of values of this annotation must be stored in -++ * {@link #parent}. -++ */ -++ private final int offset; -++ -++ /** -++ * Next annotation writer. This field is used to store annotation lists. -++ */ -++ AnnotationWriter next; -++ -++ /** -++ * Previous annotation writer. This field is used to store annotation lists. -++ */ -++ AnnotationWriter prev; -++ -++ // ------------------------------------------------------------------------ -++ // Constructor -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Constructs a new {@link AnnotationWriter}. -++ * -++ * @param cw -++ * the class writer to which this annotation must be added. -++ * @param named -++ * true if values are named, false otherwise. -++ * @param bv -++ * where the annotation values must be stored. -++ * @param parent -++ * where the number of annotation values must be stored. -++ * @param offset -++ * where in parent the number of annotation values must -++ * be stored. -++ */ -++ AnnotationWriter(final ClassWriter cw, final boolean named, -++ final ByteVector bv, final ByteVector parent, final int offset) { -++ super(Opcodes.ASM5); -++ this.cw = cw; -++ this.named = named; -++ this.bv = bv; -++ this.parent = parent; -++ this.offset = offset; -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Implementation of the AnnotationVisitor abstract class -++ // ------------------------------------------------------------------------ -++ -++ @Override -++ public void visit(final String name, final Object value) { -++ ++size; -++ if (named) { -++ bv.putShort(cw.newUTF8(name)); -++ } -++ if (value instanceof String) { -++ bv.put12('s', cw.newUTF8((String) value)); -++ } else if (value instanceof Byte) { -++ bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index); -++ } else if (value instanceof Boolean) { -++ int v = ((Boolean) value).booleanValue() ? 1 : 0; -++ bv.put12('Z', cw.newInteger(v).index); -++ } else if (value instanceof Character) { -++ bv.put12('C', cw.newInteger(((Character) value).charValue()).index); -++ } else if (value instanceof Short) { -++ bv.put12('S', cw.newInteger(((Short) value).shortValue()).index); -++ } else if (value instanceof Type) { -++ bv.put12('c', cw.newUTF8(((Type) value).getDescriptor())); -++ } else if (value instanceof byte[]) { -++ byte[] v = (byte[]) value; -++ bv.put12('[', v.length); -++ for (int i = 0; i < v.length; i++) { -++ bv.put12('B', cw.newInteger(v[i]).index); -++ } -++ } else if (value instanceof boolean[]) { -++ boolean[] v = (boolean[]) value; -++ bv.put12('[', v.length); -++ for (int i = 0; i < v.length; i++) { -++ bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index); -++ } -++ } else if (value instanceof short[]) { -++ short[] v = (short[]) value; -++ bv.put12('[', v.length); -++ for (int i = 0; i < v.length; i++) { -++ bv.put12('S', cw.newInteger(v[i]).index); -++ } -++ } else if (value instanceof char[]) { -++ char[] v = (char[]) value; -++ bv.put12('[', v.length); -++ for (int i = 0; i < v.length; i++) { -++ bv.put12('C', cw.newInteger(v[i]).index); -++ } -++ } else if (value instanceof int[]) { -++ int[] v = (int[]) value; -++ bv.put12('[', v.length); -++ for (int i = 0; i < v.length; i++) { -++ bv.put12('I', cw.newInteger(v[i]).index); -++ } -++ } else if (value instanceof long[]) { -++ long[] v = (long[]) value; -++ bv.put12('[', v.length); -++ for (int i = 0; i < v.length; i++) { -++ bv.put12('J', cw.newLong(v[i]).index); -++ } -++ } else if (value instanceof float[]) { -++ float[] v = (float[]) value; -++ bv.put12('[', v.length); -++ for (int i = 0; i < v.length; i++) { -++ bv.put12('F', cw.newFloat(v[i]).index); -++ } -++ } else if (value instanceof double[]) { -++ double[] v = (double[]) value; -++ bv.put12('[', v.length); -++ for (int i = 0; i < v.length; i++) { -++ bv.put12('D', cw.newDouble(v[i]).index); -++ } -++ } else { -++ Item i = cw.newConstItem(value); -++ bv.put12(".s.IFJDCS".charAt(i.type), i.index); -++ } -++ } -++ -++ @Override -++ public void visitEnum(final String name, final String desc, -++ final String value) { -++ ++size; -++ if (named) { -++ bv.putShort(cw.newUTF8(name)); -++ } -++ bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value)); -++ } -++ -++ @Override -++ public AnnotationVisitor visitAnnotation(final String name, -++ final String desc) { -++ ++size; -++ if (named) { -++ bv.putShort(cw.newUTF8(name)); -++ } -++ // write tag and type, and reserve space for values count -++ bv.put12('@', cw.newUTF8(desc)).putShort(0); -++ return new AnnotationWriter(cw, true, bv, bv, bv.length - 2); -++ } -++ -++ @Override -++ public AnnotationVisitor visitArray(final String name) { -++ ++size; -++ if (named) { -++ bv.putShort(cw.newUTF8(name)); -++ } -++ // write tag, and reserve space for array size -++ bv.put12('[', 0); -++ return new AnnotationWriter(cw, false, bv, bv, bv.length - 2); -++ } -++ -++ @Override -++ public void visitEnd() { -++ if (parent != null) { -++ byte[] data = parent.data; -++ data[offset] = (byte) (size >>> 8); -++ data[offset + 1] = (byte) size; -++ } -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Utility methods -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Returns the size of this annotation writer list. -++ * -++ * @return the size of this annotation writer list. -++ */ -++ int getSize() { -++ int size = 0; -++ AnnotationWriter aw = this; -++ while (aw != null) { -++ size += aw.bv.length; -++ aw = aw.next; -++ } -++ return size; -++ } -++ -++ /** -++ * Puts the annotations of this annotation writer list into the given byte -++ * vector. -++ * -++ * @param out -++ * where the annotations must be put. -++ */ -++ void put(final ByteVector out) { -++ int n = 0; -++ int size = 2; -++ AnnotationWriter aw = this; -++ AnnotationWriter last = null; -++ while (aw != null) { -++ ++n; -++ size += aw.bv.length; -++ aw.visitEnd(); // in case user forgot to call visitEnd -++ aw.prev = last; -++ last = aw; -++ aw = aw.next; -++ } -++ out.putInt(size); -++ out.putShort(n); -++ aw = last; -++ while (aw != null) { -++ out.putByteArray(aw.bv.data, 0, aw.bv.length); -++ aw = aw.prev; -++ } -++ } -++ -++ /** -++ * Puts the given annotation lists into the given byte vector. -++ * -++ * @param panns -++ * an array of annotation writer lists. -++ * @param off -++ * index of the first annotation to be written. -++ * @param out -++ * where the annotations must be put. -++ */ -++ static void put(final AnnotationWriter[] panns, final int off, -++ final ByteVector out) { -++ int size = 1 + 2 * (panns.length - off); -++ for (int i = off; i < panns.length; ++i) { -++ size += panns[i] == null ? 0 : panns[i].getSize(); -++ } -++ out.putInt(size).putByte(panns.length - off); -++ for (int i = off; i < panns.length; ++i) { -++ AnnotationWriter aw = panns[i]; -++ AnnotationWriter last = null; -++ int n = 0; -++ while (aw != null) { -++ ++n; -++ aw.visitEnd(); // in case user forgot to call visitEnd -++ aw.prev = last; -++ last = aw; -++ aw = aw.next; -++ } -++ out.putShort(n); -++ aw = last; -++ while (aw != null) { -++ out.putByteArray(aw.bv.data, 0, aw.bv.length); -++ aw = aw.prev; -++ } -++ } -++ } -++ -++ /** -++ * Puts the given type reference and type path into the given bytevector. -++ * LOCAL_VARIABLE and RESOURCE_VARIABLE target types are not supported. -++ * -++ * @param typeRef -++ * a reference to the annotated type. See {@link TypeReference}. -++ * @param typePath -++ * the path to the annotated type argument, wildcard bound, array -++ * element type, or static inner type within 'typeRef'. May be -++ * null if the annotation targets 'typeRef' as a whole. -++ * @param out -++ * where the type reference and type path must be put. -++ */ -++ static void putTarget(int typeRef, TypePath typePath, ByteVector out) { -++ switch (typeRef >>> 24) { -++ case 0x00: // CLASS_TYPE_PARAMETER -++ case 0x01: // METHOD_TYPE_PARAMETER -++ case 0x16: // METHOD_FORMAL_PARAMETER -++ out.putShort(typeRef >>> 16); -++ break; -++ case 0x13: // FIELD -++ case 0x14: // METHOD_RETURN -++ case 0x15: // METHOD_RECEIVER -++ out.putByte(typeRef >>> 24); -++ break; -++ case 0x47: // CAST -++ case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT -++ case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT -++ case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT -++ case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT -++ out.putInt(typeRef); -++ break; -++ // case 0x10: // CLASS_EXTENDS -++ // case 0x11: // CLASS_TYPE_PARAMETER_BOUND -++ // case 0x12: // METHOD_TYPE_PARAMETER_BOUND -++ // case 0x17: // THROWS -++ // case 0x42: // EXCEPTION_PARAMETER -++ // case 0x43: // INSTANCEOF -++ // case 0x44: // NEW -++ // case 0x45: // CONSTRUCTOR_REFERENCE -++ // case 0x46: // METHOD_REFERENCE -++ default: -++ out.put12(typeRef >>> 24, (typeRef & 0xFFFF00) >> 8); -++ break; -++ } -++ if (typePath == null) { -++ out.putByte(0); -++ } else { -++ int length = typePath.b[typePath.offset] * 2 + 1; -++ out.putByteArray(typePath.b, typePath.offset, length); -++ } -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/Attribute.java b/contrib/asm/src/org/objectweb/asm/Attribute.java -+new file mode 100644 -+index 0000000..8a2a882 -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/Attribute.java -+@@ -0,0 +1,255 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * A non standard class, field, method or code attribute. -++ * -++ * @author Eric Bruneton -++ * @author Eugene Kuleshov -++ */ -++public class Attribute { -++ -++ /** -++ * The type of this attribute. -++ */ -++ public final String type; -++ -++ /** -++ * The raw value of this attribute, used only for unknown attributes. -++ */ -++ byte[] value; -++ -++ /** -++ * The next attribute in this attribute list. May be null. -++ */ -++ Attribute next; -++ -++ /** -++ * Constructs a new empty attribute. -++ * -++ * @param type -++ * the type of the attribute. -++ */ -++ protected Attribute(final String type) { -++ this.type = type; -++ } -++ -++ /** -++ * Returns true if this type of attribute is unknown. The default -++ * implementation of this method always returns true. -++ * -++ * @return true if this type of attribute is unknown. -++ */ -++ public boolean isUnknown() { -++ return true; -++ } -++ -++ /** -++ * Returns true if this type of attribute is a code attribute. -++ * -++ * @return true if this type of attribute is a code attribute. -++ */ -++ public boolean isCodeAttribute() { -++ return false; -++ } -++ -++ /** -++ * Returns the labels corresponding to this attribute. -++ * -++ * @return the labels corresponding to this attribute, or null if -++ * this attribute is not a code attribute that contains labels. -++ */ -++ protected Label[] getLabels() { -++ return null; -++ } -++ -++ /** -++ * Reads a {@link #type type} attribute. This method must return a -++ * new {@link Attribute} object, of type {@link #type type}, -++ * corresponding to the len bytes starting at the given offset, in -++ * the given class reader. -++ * -++ * @param cr -++ * the class that contains the attribute to be read. -++ * @param off -++ * index of the first byte of the attribute's content in -++ * {@link ClassReader#b cr.b}. The 6 attribute header bytes, -++ * containing the type and the length of the attribute, are not -++ * taken into account here. -++ * @param len -++ * the length of the attribute's content. -++ * @param buf -++ * buffer to be used to call {@link ClassReader#readUTF8 -++ * readUTF8}, {@link ClassReader#readClass(int,char[]) readClass} -++ * or {@link ClassReader#readConst readConst}. -++ * @param codeOff -++ * index of the first byte of code's attribute content in -++ * {@link ClassReader#b cr.b}, or -1 if the attribute to be read -++ * is not a code attribute. The 6 attribute header bytes, -++ * containing the type and the length of the attribute, are not -++ * taken into account here. -++ * @param labels -++ * the labels of the method's code, or null if the -++ * attribute to be read is not a code attribute. -++ * @return a new {@link Attribute} object corresponding to the given -++ * bytes. -++ */ -++ protected Attribute read(final ClassReader cr, final int off, -++ final int len, final char[] buf, final int codeOff, -++ final Label[] labels) { -++ Attribute attr = new Attribute(type); -++ attr.value = new byte[len]; -++ System.arraycopy(cr.b, off, attr.value, 0, len); -++ return attr; -++ } -++ -++ /** -++ * Returns the byte array form of this attribute. -++ * -++ * @param cw -++ * the class to which this attribute must be added. This -++ * parameter can be used to add to the constant pool of this -++ * class the items that corresponds to this attribute. -++ * @param code -++ * the bytecode of the method corresponding to this code -++ * attribute, or null if this attribute is not a code -++ * attributes. -++ * @param len -++ * the length of the bytecode of the method corresponding to this -++ * code attribute, or null if this attribute is not a -++ * code attribute. -++ * @param maxStack -++ * the maximum stack size of the method corresponding to this -++ * code attribute, or -1 if this attribute is not a code -++ * attribute. -++ * @param maxLocals -++ * the maximum number of local variables of the method -++ * corresponding to this code attribute, or -1 if this attribute -++ * is not a code attribute. -++ * @return the byte array form of this attribute. -++ */ -++ protected ByteVector write(final ClassWriter cw, final byte[] code, -++ final int len, final int maxStack, final int maxLocals) { -++ ByteVector v = new ByteVector(); -++ v.data = value; -++ v.length = value.length; -++ return v; -++ } -++ -++ /** -++ * Returns the length of the attribute list that begins with this attribute. -++ * -++ * @return the length of the attribute list that begins with this attribute. -++ */ -++ final int getCount() { -++ int count = 0; -++ Attribute attr = this; -++ while (attr != null) { -++ count += 1; -++ attr = attr.next; -++ } -++ return count; -++ } -++ -++ /** -++ * Returns the size of all the attributes in this attribute list. -++ * -++ * @param cw -++ * the class writer to be used to convert the attributes into -++ * byte arrays, with the {@link #write write} method. -++ * @param code -++ * the bytecode of the method corresponding to these code -++ * attributes, or null if these attributes are not code -++ * attributes. -++ * @param len -++ * the length of the bytecode of the method corresponding to -++ * these code attributes, or null if these attributes -++ * are not code attributes. -++ * @param maxStack -++ * the maximum stack size of the method corresponding to these -++ * code attributes, or -1 if these attributes are not code -++ * attributes. -++ * @param maxLocals -++ * the maximum number of local variables of the method -++ * corresponding to these code attributes, or -1 if these -++ * attributes are not code attributes. -++ * @return the size of all the attributes in this attribute list. This size -++ * includes the size of the attribute headers. -++ */ -++ final int getSize(final ClassWriter cw, final byte[] code, final int len, -++ final int maxStack, final int maxLocals) { -++ Attribute attr = this; -++ int size = 0; -++ while (attr != null) { -++ cw.newUTF8(attr.type); -++ size += attr.write(cw, code, len, maxStack, maxLocals).length + 6; -++ attr = attr.next; -++ } -++ return size; -++ } -++ -++ /** -++ * Writes all the attributes of this attribute list in the given byte -++ * vector. -++ * -++ * @param cw -++ * the class writer to be used to convert the attributes into -++ * byte arrays, with the {@link #write write} method. -++ * @param code -++ * the bytecode of the method corresponding to these code -++ * attributes, or null if these attributes are not code -++ * attributes. -++ * @param len -++ * the length of the bytecode of the method corresponding to -++ * these code attributes, or null if these attributes -++ * are not code attributes. -++ * @param maxStack -++ * the maximum stack size of the method corresponding to these -++ * code attributes, or -1 if these attributes are not code -++ * attributes. -++ * @param maxLocals -++ * the maximum number of local variables of the method -++ * corresponding to these code attributes, or -1 if these -++ * attributes are not code attributes. -++ * @param out -++ * where the attributes must be written. -++ */ -++ final void put(final ClassWriter cw, final byte[] code, final int len, -++ final int maxStack, final int maxLocals, final ByteVector out) { -++ Attribute attr = this; -++ while (attr != null) { -++ ByteVector b = attr.write(cw, code, len, maxStack, maxLocals); -++ out.putShort(cw.newUTF8(attr.type)).putInt(b.length); -++ out.putByteArray(b.data, 0, b.length); -++ attr = attr.next; -++ } -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/ByteVector.java b/contrib/asm/src/org/objectweb/asm/ByteVector.java -+new file mode 100644 -+index 0000000..9c532be -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/ByteVector.java -+@@ -0,0 +1,339 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * A dynamically extensible vector of bytes. This class is roughly equivalent to -++ * a DataOutputStream on top of a ByteArrayOutputStream, but is more efficient. -++ * -++ * @author Eric Bruneton -++ */ -++public class ByteVector { -++ -++ /** -++ * The content of this vector. -++ */ -++ byte[] data; -++ -++ /** -++ * Actual number of bytes in this vector. -++ */ -++ int length; -++ -++ /** -++ * Constructs a new {@link ByteVector ByteVector} with a default initial -++ * size. -++ */ -++ public ByteVector() { -++ data = new byte[64]; -++ } -++ -++ /** -++ * Constructs a new {@link ByteVector ByteVector} with the given initial -++ * size. -++ * -++ * @param initialSize -++ * the initial size of the byte vector to be constructed. -++ */ -++ public ByteVector(final int initialSize) { -++ data = new byte[initialSize]; -++ } -++ -++ /** -++ * Puts a byte into this byte vector. The byte vector is automatically -++ * enlarged if necessary. -++ * -++ * @param b -++ * a byte. -++ * @return this byte vector. -++ */ -++ public ByteVector putByte(final int b) { -++ int length = this.length; -++ if (length + 1 > data.length) { -++ enlarge(1); -++ } -++ data[length++] = (byte) b; -++ this.length = length; -++ return this; -++ } -++ -++ /** -++ * Puts two bytes into this byte vector. The byte vector is automatically -++ * enlarged if necessary. -++ * -++ * @param b1 -++ * a byte. -++ * @param b2 -++ * another byte. -++ * @return this byte vector. -++ */ -++ ByteVector put11(final int b1, final int b2) { -++ int length = this.length; -++ if (length + 2 > data.length) { -++ enlarge(2); -++ } -++ byte[] data = this.data; -++ data[length++] = (byte) b1; -++ data[length++] = (byte) b2; -++ this.length = length; -++ return this; -++ } -++ -++ /** -++ * Puts a short into this byte vector. The byte vector is automatically -++ * enlarged if necessary. -++ * -++ * @param s -++ * a short. -++ * @return this byte vector. -++ */ -++ public ByteVector putShort(final int s) { -++ int length = this.length; -++ if (length + 2 > data.length) { -++ enlarge(2); -++ } -++ byte[] data = this.data; -++ data[length++] = (byte) (s >>> 8); -++ data[length++] = (byte) s; -++ this.length = length; -++ return this; -++ } -++ -++ /** -++ * Puts a byte and a short into this byte vector. The byte vector is -++ * automatically enlarged if necessary. -++ * -++ * @param b -++ * a byte. -++ * @param s -++ * a short. -++ * @return this byte vector. -++ */ -++ ByteVector put12(final int b, final int s) { -++ int length = this.length; -++ if (length + 3 > data.length) { -++ enlarge(3); -++ } -++ byte[] data = this.data; -++ data[length++] = (byte) b; -++ data[length++] = (byte) (s >>> 8); -++ data[length++] = (byte) s; -++ this.length = length; -++ return this; -++ } -++ -++ /** -++ * Puts an int into this byte vector. The byte vector is automatically -++ * enlarged if necessary. -++ * -++ * @param i -++ * an int. -++ * @return this byte vector. -++ */ -++ public ByteVector putInt(final int i) { -++ int length = this.length; -++ if (length + 4 > data.length) { -++ enlarge(4); -++ } -++ byte[] data = this.data; -++ data[length++] = (byte) (i >>> 24); -++ data[length++] = (byte) (i >>> 16); -++ data[length++] = (byte) (i >>> 8); -++ data[length++] = (byte) i; -++ this.length = length; -++ return this; -++ } -++ -++ /** -++ * Puts a long into this byte vector. The byte vector is automatically -++ * enlarged if necessary. -++ * -++ * @param l -++ * a long. -++ * @return this byte vector. -++ */ -++ public ByteVector putLong(final long l) { -++ int length = this.length; -++ if (length + 8 > data.length) { -++ enlarge(8); -++ } -++ byte[] data = this.data; -++ int i = (int) (l >>> 32); -++ data[length++] = (byte) (i >>> 24); -++ data[length++] = (byte) (i >>> 16); -++ data[length++] = (byte) (i >>> 8); -++ data[length++] = (byte) i; -++ i = (int) l; -++ data[length++] = (byte) (i >>> 24); -++ data[length++] = (byte) (i >>> 16); -++ data[length++] = (byte) (i >>> 8); -++ data[length++] = (byte) i; -++ this.length = length; -++ return this; -++ } -++ -++ /** -++ * Puts an UTF8 string into this byte vector. The byte vector is -++ * automatically enlarged if necessary. -++ * -++ * @param s -++ * a String whose UTF8 encoded length must be less than 65536. -++ * @return this byte vector. -++ */ -++ public ByteVector putUTF8(final String s) { -++ int charLength = s.length(); -++ if (charLength > 65535) { -++ throw new IllegalArgumentException(); -++ } -++ int len = length; -++ if (len + 2 + charLength > data.length) { -++ enlarge(2 + charLength); -++ } -++ byte[] data = this.data; -++ // optimistic algorithm: instead of computing the byte length and then -++ // serializing the string (which requires two loops), we assume the byte -++ // length is equal to char length (which is the most frequent case), and -++ // we start serializing the string right away. During the serialization, -++ // if we find that this assumption is wrong, we continue with the -++ // general method. -++ data[len++] = (byte) (charLength >>> 8); -++ data[len++] = (byte) charLength; -++ for (int i = 0; i < charLength; ++i) { -++ char c = s.charAt(i); -++ if (c >= '\001' && c <= '\177') { -++ data[len++] = (byte) c; -++ } else { -++ length = len; -++ return encodeUTF8(s, i, 65535); -++ } -++ } -++ length = len; -++ return this; -++ } -++ -++ /** -++ * Puts an UTF8 string into this byte vector. The byte vector is -++ * automatically enlarged if necessary. The string length is encoded in two -++ * bytes before the encoded characters, if there is space for that (i.e. if -++ * this.length - i - 2 >= 0). -++ * -++ * @param s -++ * the String to encode. -++ * @param i -++ * the index of the first character to encode. The previous -++ * characters are supposed to have already been encoded, using -++ * only one byte per character. -++ * @param maxByteLength -++ * the maximum byte length of the encoded string, including the -++ * already encoded characters. -++ * @return this byte vector. -++ */ -++ ByteVector encodeUTF8(final String s, int i, int maxByteLength) { -++ int charLength = s.length(); -++ int byteLength = i; -++ char c; -++ for (int j = i; j < charLength; ++j) { -++ c = s.charAt(j); -++ if (c >= '\001' && c <= '\177') { -++ byteLength++; -++ } else if (c > '\u07FF') { -++ byteLength += 3; -++ } else { -++ byteLength += 2; -++ } -++ } -++ if (byteLength > maxByteLength) { -++ throw new IllegalArgumentException(); -++ } -++ int start = length - i - 2; -++ if (start >= 0) { -++ data[start] = (byte) (byteLength >>> 8); -++ data[start + 1] = (byte) byteLength; -++ } -++ if (length + byteLength - i > data.length) { -++ enlarge(byteLength - i); -++ } -++ int len = length; -++ for (int j = i; j < charLength; ++j) { -++ c = s.charAt(j); -++ if (c >= '\001' && c <= '\177') { -++ data[len++] = (byte) c; -++ } else if (c > '\u07FF') { -++ data[len++] = (byte) (0xE0 | c >> 12 & 0xF); -++ data[len++] = (byte) (0x80 | c >> 6 & 0x3F); -++ data[len++] = (byte) (0x80 | c & 0x3F); -++ } else { -++ data[len++] = (byte) (0xC0 | c >> 6 & 0x1F); -++ data[len++] = (byte) (0x80 | c & 0x3F); -++ } -++ } -++ length = len; -++ return this; -++ } -++ -++ /** -++ * Puts an array of bytes into this byte vector. The byte vector is -++ * automatically enlarged if necessary. -++ * -++ * @param b -++ * an array of bytes. May be null to put len -++ * null bytes into this byte vector. -++ * @param off -++ * index of the fist byte of b that must be copied. -++ * @param len -++ * number of bytes of b that must be copied. -++ * @return this byte vector. -++ */ -++ public ByteVector putByteArray(final byte[] b, final int off, final int len) { -++ if (length + len > data.length) { -++ enlarge(len); -++ } -++ if (b != null) { -++ System.arraycopy(b, off, data, length, len); -++ } -++ length += len; -++ return this; -++ } -++ -++ /** -++ * Enlarge this byte vector so that it can receive n more bytes. -++ * -++ * @param size -++ * number of additional bytes that this byte vector should be -++ * able to receive. -++ */ -++ private void enlarge(final int size) { -++ int length1 = 2 * data.length; -++ int length2 = length + size; -++ byte[] newData = new byte[length1 > length2 ? length1 : length2]; -++ System.arraycopy(data, 0, newData, 0, length); -++ data = newData; -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/ClassReader.java b/contrib/asm/src/org/objectweb/asm/ClassReader.java -+new file mode 100644 -+index 0000000..e23fd60 -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/ClassReader.java -+@@ -0,0 +1,2506 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++import java.io.IOException; -++import java.io.InputStream; -++ -++/** -++ * A Java class parser to make a {@link ClassVisitor} visit an existing class. -++ * This class parses a byte array conforming to the Java class file format and -++ * calls the appropriate visit methods of a given class visitor for each field, -++ * method and bytecode instruction encountered. -++ * -++ * @author Eric Bruneton -++ * @author Eugene Kuleshov -++ */ -++public class ClassReader { -++ -++ /** -++ * True to enable signatures support. -++ */ -++ static final boolean SIGNATURES = true; -++ -++ /** -++ * True to enable annotations support. -++ */ -++ static final boolean ANNOTATIONS = true; -++ -++ /** -++ * True to enable stack map frames support. -++ */ -++ static final boolean FRAMES = true; -++ -++ /** -++ * True to enable bytecode writing support. -++ */ -++ static final boolean WRITER = true; -++ -++ /** -++ * True to enable JSR_W and GOTO_W support. -++ */ -++ static final boolean RESIZE = true; -++ -++ /** -++ * Flag to skip method code. If this class is set CODE -++ * attribute won't be visited. This can be used, for example, to retrieve -++ * annotations for methods and method parameters. -++ */ -++ public static final int SKIP_CODE = 1; -++ -++ /** -++ * Flag to skip the debug information in the class. If this flag is set the -++ * debug information of the class is not visited, i.e. the -++ * {@link MethodVisitor#visitLocalVariable visitLocalVariable} and -++ * {@link MethodVisitor#visitLineNumber visitLineNumber} methods will not be -++ * called. -++ */ -++ public static final int SKIP_DEBUG = 2; -++ -++ /** -++ * Flag to skip the stack map frames in the class. If this flag is set the -++ * stack map frames of the class is not visited, i.e. the -++ * {@link MethodVisitor#visitFrame visitFrame} method will not be called. -++ * This flag is useful when the {@link ClassWriter#COMPUTE_FRAMES} option is -++ * used: it avoids visiting frames that will be ignored and recomputed from -++ * scratch in the class writer. -++ */ -++ public static final int SKIP_FRAMES = 4; -++ -++ /** -++ * Flag to expand the stack map frames. By default stack map frames are -++ * visited in their original format (i.e. "expanded" for classes whose -++ * version is less than V1_6, and "compressed" for the other classes). If -++ * this flag is set, stack map frames are always visited in expanded format -++ * (this option adds a decompression/recompression step in ClassReader and -++ * ClassWriter which degrades performances quite a lot). -++ */ -++ public static final int EXPAND_FRAMES = 8; -++ -++ /** -++ * The class to be parsed. The content of this array must not be -++ * modified. This field is intended for {@link Attribute} sub classes, and -++ * is normally not needed by class generators or adapters. -++ */ -++ public final byte[] b; -++ -++ /** -++ * The start index of each constant pool item in {@link #b b}, plus one. The -++ * one byte offset skips the constant pool item tag that indicates its type. -++ */ -++ private final int[] items; -++ -++ /** -++ * The String objects corresponding to the CONSTANT_Utf8 items. This cache -++ * avoids multiple parsing of a given CONSTANT_Utf8 constant pool item, -++ * which GREATLY improves performances (by a factor 2 to 3). This caching -++ * strategy could be extended to all constant pool items, but its benefit -++ * would not be so great for these items (because they are much less -++ * expensive to parse than CONSTANT_Utf8 items). -++ */ -++ private final String[] strings; -++ -++ /** -++ * Maximum length of the strings contained in the constant pool of the -++ * class. -++ */ -++ private final int maxStringLength; -++ -++ /** -++ * Start index of the class header information (access, name...) in -++ * {@link #b b}. -++ */ -++ public final int header; -++ -++ // ------------------------------------------------------------------------ -++ // Constructors -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Constructs a new {@link ClassReader} object. -++ * -++ * @param b -++ * the bytecode of the class to be read. -++ */ -++ public ClassReader(final byte[] b) { -++ this(b, 0, b.length); -++ } -++ -++ /** -++ * Constructs a new {@link ClassReader} object. -++ * -++ * @param b -++ * the bytecode of the class to be read. -++ * @param off -++ * the start offset of the class data. -++ * @param len -++ * the length of the class data. -++ */ -++ public ClassReader(final byte[] b, final int off, final int len) { -++ this.b = b; -++ // checks the class version -++ if (readShort(off + 6) > Opcodes.V1_8) { -++ throw new IllegalArgumentException(); -++ } -++ // parses the constant pool -++ items = new int[readUnsignedShort(off + 8)]; -++ int n = items.length; -++ strings = new String[n]; -++ int max = 0; -++ int index = off + 10; -++ for (int i = 1; i < n; ++i) { -++ items[i] = index + 1; -++ int size; -++ switch (b[index]) { -++ case ClassWriter.FIELD: -++ case ClassWriter.METH: -++ case ClassWriter.IMETH: -++ case ClassWriter.INT: -++ case ClassWriter.FLOAT: -++ case ClassWriter.NAME_TYPE: -++ case ClassWriter.INDY: -++ size = 5; -++ break; -++ case ClassWriter.LONG: -++ case ClassWriter.DOUBLE: -++ size = 9; -++ ++i; -++ break; -++ case ClassWriter.UTF8: -++ size = 3 + readUnsignedShort(index + 1); -++ if (size > max) { -++ max = size; -++ } -++ break; -++ case ClassWriter.HANDLE: -++ size = 4; -++ break; -++ // case ClassWriter.CLASS: -++ // case ClassWriter.STR: -++ // case ClassWriter.MTYPE -++ default: -++ size = 3; -++ break; -++ } -++ index += size; -++ } -++ maxStringLength = max; -++ // the class header information starts just after the constant pool -++ header = index; -++ } -++ -++ /** -++ * Returns the class's access flags (see {@link Opcodes}). This value may -++ * not reflect Deprecated and Synthetic flags when bytecode is before 1.5 -++ * and those flags are represented by attributes. -++ * -++ * @return the class access flags -++ * -++ * @see ClassVisitor#visit(int, int, String, String, String, String[]) -++ */ -++ public int getAccess() { -++ return readUnsignedShort(header); -++ } -++ -++ /** -++ * Returns the internal name of the class (see -++ * {@link Type#getInternalName() getInternalName}). -++ * -++ * @return the internal class name -++ * -++ * @see ClassVisitor#visit(int, int, String, String, String, String[]) -++ */ -++ public String getClassName() { -++ return readClass(header + 2, new char[maxStringLength]); -++ } -++ -++ /** -++ * Returns the internal of name of the super class (see -++ * {@link Type#getInternalName() getInternalName}). For interfaces, the -++ * super class is {@link Object}. -++ * -++ * @return the internal name of super class, or null for -++ * {@link Object} class. -++ * -++ * @see ClassVisitor#visit(int, int, String, String, String, String[]) -++ */ -++ public String getSuperName() { -++ return readClass(header + 4, new char[maxStringLength]); -++ } -++ -++ /** -++ * Returns the internal names of the class's interfaces (see -++ * {@link Type#getInternalName() getInternalName}). -++ * -++ * @return the array of internal names for all implemented interfaces or -++ * null. -++ * -++ * @see ClassVisitor#visit(int, int, String, String, String, String[]) -++ */ -++ public String[] getInterfaces() { -++ int index = header + 6; -++ int n = readUnsignedShort(index); -++ String[] interfaces = new String[n]; -++ if (n > 0) { -++ char[] buf = new char[maxStringLength]; -++ for (int i = 0; i < n; ++i) { -++ index += 2; -++ interfaces[i] = readClass(index, buf); -++ } -++ } -++ return interfaces; -++ } -++ -++ /** -++ * Copies the constant pool data into the given {@link ClassWriter}. Should -++ * be called before the {@link #accept(ClassVisitor,int)} method. -++ * -++ * @param classWriter -++ * the {@link ClassWriter} to copy constant pool into. -++ */ -++ void copyPool(final ClassWriter classWriter) { -++ char[] buf = new char[maxStringLength]; -++ int ll = items.length; -++ Item[] items2 = new Item[ll]; -++ for (int i = 1; i < ll; i++) { -++ int index = items[i]; -++ int tag = b[index - 1]; -++ Item item = new Item(i); -++ int nameType; -++ switch (tag) { -++ case ClassWriter.FIELD: -++ case ClassWriter.METH: -++ case ClassWriter.IMETH: -++ nameType = items[readUnsignedShort(index + 2)]; -++ item.set(tag, readClass(index, buf), readUTF8(nameType, buf), -++ readUTF8(nameType + 2, buf)); -++ break; -++ case ClassWriter.INT: -++ item.set(readInt(index)); -++ break; -++ case ClassWriter.FLOAT: -++ item.set(Float.intBitsToFloat(readInt(index))); -++ break; -++ case ClassWriter.NAME_TYPE: -++ item.set(tag, readUTF8(index, buf), readUTF8(index + 2, buf), -++ null); -++ break; -++ case ClassWriter.LONG: -++ item.set(readLong(index)); -++ ++i; -++ break; -++ case ClassWriter.DOUBLE: -++ item.set(Double.longBitsToDouble(readLong(index))); -++ ++i; -++ break; -++ case ClassWriter.UTF8: { -++ String s = strings[i]; -++ if (s == null) { -++ index = items[i]; -++ s = strings[i] = readUTF(index + 2, -++ readUnsignedShort(index), buf); -++ } -++ item.set(tag, s, null, null); -++ break; -++ } -++ case ClassWriter.HANDLE: { -++ int fieldOrMethodRef = items[readUnsignedShort(index + 1)]; -++ nameType = items[readUnsignedShort(fieldOrMethodRef + 2)]; -++ item.set(ClassWriter.HANDLE_BASE + readByte(index), -++ readClass(fieldOrMethodRef, buf), -++ readUTF8(nameType, buf), readUTF8(nameType + 2, buf)); -++ break; -++ } -++ case ClassWriter.INDY: -++ if (classWriter.bootstrapMethods == null) { -++ copyBootstrapMethods(classWriter, items2, buf); -++ } -++ nameType = items[readUnsignedShort(index + 2)]; -++ item.set(readUTF8(nameType, buf), readUTF8(nameType + 2, buf), -++ readUnsignedShort(index)); -++ break; -++ // case ClassWriter.STR: -++ // case ClassWriter.CLASS: -++ // case ClassWriter.MTYPE -++ default: -++ item.set(tag, readUTF8(index, buf), null, null); -++ break; -++ } -++ -++ int index2 = item.hashCode % items2.length; -++ item.next = items2[index2]; -++ items2[index2] = item; -++ } -++ -++ int off = items[1] - 1; -++ classWriter.pool.putByteArray(b, off, header - off); -++ classWriter.items = items2; -++ classWriter.threshold = (int) (0.75d * ll); -++ classWriter.index = ll; -++ } -++ -++ /** -++ * Copies the bootstrap method data into the given {@link ClassWriter}. -++ * Should be called before the {@link #accept(ClassVisitor,int)} method. -++ * -++ * @param classWriter -++ * the {@link ClassWriter} to copy bootstrap methods into. -++ */ -++ private void copyBootstrapMethods(final ClassWriter classWriter, -++ final Item[] items, final char[] c) { -++ // finds the "BootstrapMethods" attribute -++ int u = getAttributes(); -++ boolean found = false; -++ for (int i = readUnsignedShort(u); i > 0; --i) { -++ String attrName = readUTF8(u + 2, c); -++ if ("BootstrapMethods".equals(attrName)) { -++ found = true; -++ break; -++ } -++ u += 6 + readInt(u + 4); -++ } -++ if (!found) { -++ return; -++ } -++ // copies the bootstrap methods in the class writer -++ int boostrapMethodCount = readUnsignedShort(u + 8); -++ for (int j = 0, v = u + 10; j < boostrapMethodCount; j++) { -++ int position = v - u - 10; -++ int hashCode = readConst(readUnsignedShort(v), c).hashCode(); -++ for (int k = readUnsignedShort(v + 2); k > 0; --k) { -++ hashCode ^= readConst(readUnsignedShort(v + 4), c).hashCode(); -++ v += 2; -++ } -++ v += 4; -++ Item item = new Item(j); -++ item.set(position, hashCode & 0x7FFFFFFF); -++ int index = item.hashCode % items.length; -++ item.next = items[index]; -++ items[index] = item; -++ } -++ int attrSize = readInt(u + 4); -++ ByteVector bootstrapMethods = new ByteVector(attrSize + 62); -++ bootstrapMethods.putByteArray(b, u + 10, attrSize - 2); -++ classWriter.bootstrapMethodsCount = boostrapMethodCount; -++ classWriter.bootstrapMethods = bootstrapMethods; -++ } -++ -++ /** -++ * Constructs a new {@link ClassReader} object. -++ * -++ * @param is -++ * an input stream from which to read the class. -++ * @throws IOException -++ * if a problem occurs during reading. -++ */ -++ public ClassReader(final InputStream is) throws IOException { -++ this(readClass(is, false)); -++ } -++ -++ /** -++ * Constructs a new {@link ClassReader} object. -++ * -++ * @param name -++ * the binary qualified name of the class to be read. -++ * @throws IOException -++ * if an exception occurs during reading. -++ */ -++ public ClassReader(final String name) throws IOException { -++ this(readClass( -++ ClassLoader.getSystemResourceAsStream(name.replace('.', '/') -++ + ".class"), true)); -++ } -++ -++ /** -++ * Reads the bytecode of a class. -++ * -++ * @param is -++ * an input stream from which to read the class. -++ * @param close -++ * true to close the input stream after reading. -++ * @return the bytecode read from the given input stream. -++ * @throws IOException -++ * if a problem occurs during reading. -++ */ -++ private static byte[] readClass(final InputStream is, boolean close) -++ throws IOException { -++ if (is == null) { -++ throw new IOException("Class not found"); -++ } -++ try { -++ byte[] b = new byte[is.available()]; -++ int len = 0; -++ while (true) { -++ int n = is.read(b, len, b.length - len); -++ if (n == -1) { -++ if (len < b.length) { -++ byte[] c = new byte[len]; -++ System.arraycopy(b, 0, c, 0, len); -++ b = c; -++ } -++ return b; -++ } -++ len += n; -++ if (len == b.length) { -++ int last = is.read(); -++ if (last < 0) { -++ return b; -++ } -++ byte[] c = new byte[b.length + 1000]; -++ System.arraycopy(b, 0, c, 0, len); -++ c[len++] = (byte) last; -++ b = c; -++ } -++ } -++ } finally { -++ if (close) { -++ is.close(); -++ } -++ } -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Public methods -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Makes the given visitor visit the Java class of this {@link ClassReader} -++ * . This class is the one specified in the constructor (see -++ * {@link #ClassReader(byte[]) ClassReader}). -++ * -++ * @param classVisitor -++ * the visitor that must visit this class. -++ * @param flags -++ * option flags that can be used to modify the default behavior -++ * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES} -++ * , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}. -++ */ -++ public void accept(final ClassVisitor classVisitor, final int flags) { -++ accept(classVisitor, new Attribute[0], flags); -++ } -++ -++ /** -++ * Makes the given visitor visit the Java class of this {@link ClassReader}. -++ * This class is the one specified in the constructor (see -++ * {@link #ClassReader(byte[]) ClassReader}). -++ * -++ * @param classVisitor -++ * the visitor that must visit this class. -++ * @param attrs -++ * prototypes of the attributes that must be parsed during the -++ * visit of the class. Any attribute whose type is not equal to -++ * the type of one the prototypes will not be parsed: its byte -++ * array value will be passed unchanged to the ClassWriter. -++ * This may corrupt it if this value contains references to -++ * the constant pool, or has syntactic or semantic links with a -++ * class element that has been transformed by a class adapter -++ * between the reader and the writer. -++ * @param flags -++ * option flags that can be used to modify the default behavior -++ * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES} -++ * , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}. -++ */ -++ public void accept(final ClassVisitor classVisitor, -++ final Attribute[] attrs, final int flags) { -++ int u = header; // current offset in the class file -++ char[] c = new char[maxStringLength]; // buffer used to read strings -++ -++ Context context = new Context(); -++ context.attrs = attrs; -++ context.flags = flags; -++ context.buffer = c; -++ -++ // reads the class declaration -++ int access = readUnsignedShort(u); -++ String name = readClass(u + 2, c); -++ String superClass = readClass(u + 4, c); -++ String[] interfaces = new String[readUnsignedShort(u + 6)]; -++ u += 8; -++ for (int i = 0; i < interfaces.length; ++i) { -++ interfaces[i] = readClass(u, c); -++ u += 2; -++ } -++ -++ // reads the class attributes -++ String signature = null; -++ String sourceFile = null; -++ String sourceDebug = null; -++ String enclosingOwner = null; -++ String enclosingName = null; -++ String enclosingDesc = null; -++ int anns = 0; -++ int ianns = 0; -++ int tanns = 0; -++ int itanns = 0; -++ int innerClasses = 0; -++ Attribute attributes = null; -++ -++ u = getAttributes(); -++ for (int i = readUnsignedShort(u); i > 0; --i) { -++ String attrName = readUTF8(u + 2, c); -++ // tests are sorted in decreasing frequency order -++ // (based on frequencies observed on typical classes) -++ if ("SourceFile".equals(attrName)) { -++ sourceFile = readUTF8(u + 8, c); -++ } else if ("InnerClasses".equals(attrName)) { -++ innerClasses = u + 8; -++ } else if ("EnclosingMethod".equals(attrName)) { -++ enclosingOwner = readClass(u + 8, c); -++ int item = readUnsignedShort(u + 10); -++ if (item != 0) { -++ enclosingName = readUTF8(items[item], c); -++ enclosingDesc = readUTF8(items[item] + 2, c); -++ } -++ } else if (SIGNATURES && "Signature".equals(attrName)) { -++ signature = readUTF8(u + 8, c); -++ } else if (ANNOTATIONS -++ && "RuntimeVisibleAnnotations".equals(attrName)) { -++ anns = u + 8; -++ } else if (ANNOTATIONS -++ && "RuntimeVisibleTypeAnnotations".equals(attrName)) { -++ tanns = u + 8; -++ } else if ("Deprecated".equals(attrName)) { -++ access |= Opcodes.ACC_DEPRECATED; -++ } else if ("Synthetic".equals(attrName)) { -++ access |= Opcodes.ACC_SYNTHETIC -++ | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; -++ } else if ("SourceDebugExtension".equals(attrName)) { -++ int len = readInt(u + 4); -++ sourceDebug = readUTF(u + 8, len, new char[len]); -++ } else if (ANNOTATIONS -++ && "RuntimeInvisibleAnnotations".equals(attrName)) { -++ ianns = u + 8; -++ } else if (ANNOTATIONS -++ && "RuntimeInvisibleTypeAnnotations".equals(attrName)) { -++ itanns = u + 8; -++ } else if ("BootstrapMethods".equals(attrName)) { -++ int[] bootstrapMethods = new int[readUnsignedShort(u + 8)]; -++ for (int j = 0, v = u + 10; j < bootstrapMethods.length; j++) { -++ bootstrapMethods[j] = v; -++ v += 2 + readUnsignedShort(v + 2) << 1; -++ } -++ context.bootstrapMethods = bootstrapMethods; -++ } else { -++ Attribute attr = readAttribute(attrs, attrName, u + 8, -++ readInt(u + 4), c, -1, null); -++ if (attr != null) { -++ attr.next = attributes; -++ attributes = attr; -++ } -++ } -++ u += 6 + readInt(u + 4); -++ } -++ -++ // visits the class declaration -++ classVisitor.visit(readInt(items[1] - 7), access, name, signature, -++ superClass, interfaces); -++ -++ // visits the source and debug info -++ if ((flags & SKIP_DEBUG) == 0 -++ && (sourceFile != null || sourceDebug != null)) { -++ classVisitor.visitSource(sourceFile, sourceDebug); -++ } -++ -++ // visits the outer class -++ if (enclosingOwner != null) { -++ classVisitor.visitOuterClass(enclosingOwner, enclosingName, -++ enclosingDesc); -++ } -++ -++ // visits the class annotations and type annotations -++ if (ANNOTATIONS && anns != 0) { -++ for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) { -++ v = readAnnotationValues(v + 2, c, true, -++ classVisitor.visitAnnotation(readUTF8(v, c), true)); -++ } -++ } -++ if (ANNOTATIONS && ianns != 0) { -++ for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) { -++ v = readAnnotationValues(v + 2, c, true, -++ classVisitor.visitAnnotation(readUTF8(v, c), false)); -++ } -++ } -++ if (ANNOTATIONS && tanns != 0) { -++ for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { -++ v = readAnnotationTarget(context, v); -++ v = readAnnotationValues(v + 2, c, true, -++ classVisitor.visitTypeAnnotation(context.typeRef, -++ context.typePath, readUTF8(v, c), true)); -++ } -++ } -++ if (ANNOTATIONS && itanns != 0) { -++ for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { -++ v = readAnnotationTarget(context, v); -++ v = readAnnotationValues(v + 2, c, true, -++ classVisitor.visitTypeAnnotation(context.typeRef, -++ context.typePath, readUTF8(v, c), false)); -++ } -++ } -++ -++ // visits the attributes -++ while (attributes != null) { -++ Attribute attr = attributes.next; -++ attributes.next = null; -++ classVisitor.visitAttribute(attributes); -++ attributes = attr; -++ } -++ -++ // visits the inner classes -++ if (innerClasses != 0) { -++ int v = innerClasses + 2; -++ for (int i = readUnsignedShort(innerClasses); i > 0; --i) { -++ classVisitor.visitInnerClass(readClass(v, c), -++ readClass(v + 2, c), readUTF8(v + 4, c), -++ readUnsignedShort(v + 6)); -++ v += 8; -++ } -++ } -++ -++ // visits the fields and methods -++ u = header + 10 + 2 * interfaces.length; -++ for (int i = readUnsignedShort(u - 2); i > 0; --i) { -++ u = readField(classVisitor, context, u); -++ } -++ u += 2; -++ for (int i = readUnsignedShort(u - 2); i > 0; --i) { -++ u = readMethod(classVisitor, context, u); -++ } -++ -++ // visits the end of the class -++ classVisitor.visitEnd(); -++ } -++ -++ /** -++ * Reads a field and makes the given visitor visit it. -++ * -++ * @param classVisitor -++ * the visitor that must visit the field. -++ * @param context -++ * information about the class being parsed. -++ * @param u -++ * the start offset of the field in the class file. -++ * @return the offset of the first byte following the field in the class. -++ */ -++ private int readField(final ClassVisitor classVisitor, -++ final Context context, int u) { -++ // reads the field declaration -++ char[] c = context.buffer; -++ int access = readUnsignedShort(u); -++ String name = readUTF8(u + 2, c); -++ String desc = readUTF8(u + 4, c); -++ u += 6; -++ -++ // reads the field attributes -++ String signature = null; -++ int anns = 0; -++ int ianns = 0; -++ int tanns = 0; -++ int itanns = 0; -++ Object value = null; -++ Attribute attributes = null; -++ -++ for (int i = readUnsignedShort(u); i > 0; --i) { -++ String attrName = readUTF8(u + 2, c); -++ // tests are sorted in decreasing frequency order -++ // (based on frequencies observed on typical classes) -++ if ("ConstantValue".equals(attrName)) { -++ int item = readUnsignedShort(u + 8); -++ value = item == 0 ? null : readConst(item, c); -++ } else if (SIGNATURES && "Signature".equals(attrName)) { -++ signature = readUTF8(u + 8, c); -++ } else if ("Deprecated".equals(attrName)) { -++ access |= Opcodes.ACC_DEPRECATED; -++ } else if ("Synthetic".equals(attrName)) { -++ access |= Opcodes.ACC_SYNTHETIC -++ | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; -++ } else if (ANNOTATIONS -++ && "RuntimeVisibleAnnotations".equals(attrName)) { -++ anns = u + 8; -++ } else if (ANNOTATIONS -++ && "RuntimeVisibleTypeAnnotations".equals(attrName)) { -++ tanns = u + 8; -++ } else if (ANNOTATIONS -++ && "RuntimeInvisibleAnnotations".equals(attrName)) { -++ ianns = u + 8; -++ } else if (ANNOTATIONS -++ && "RuntimeInvisibleTypeAnnotations".equals(attrName)) { -++ itanns = u + 8; -++ } else { -++ Attribute attr = readAttribute(context.attrs, attrName, u + 8, -++ readInt(u + 4), c, -1, null); -++ if (attr != null) { -++ attr.next = attributes; -++ attributes = attr; -++ } -++ } -++ u += 6 + readInt(u + 4); -++ } -++ u += 2; -++ -++ // visits the field declaration -++ FieldVisitor fv = classVisitor.visitField(access, name, desc, -++ signature, value); -++ if (fv == null) { -++ return u; -++ } -++ -++ // visits the field annotations and type annotations -++ if (ANNOTATIONS && anns != 0) { -++ for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) { -++ v = readAnnotationValues(v + 2, c, true, -++ fv.visitAnnotation(readUTF8(v, c), true)); -++ } -++ } -++ if (ANNOTATIONS && ianns != 0) { -++ for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) { -++ v = readAnnotationValues(v + 2, c, true, -++ fv.visitAnnotation(readUTF8(v, c), false)); -++ } -++ } -++ if (ANNOTATIONS && tanns != 0) { -++ for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { -++ v = readAnnotationTarget(context, v); -++ v = readAnnotationValues(v + 2, c, true, -++ fv.visitTypeAnnotation(context.typeRef, -++ context.typePath, readUTF8(v, c), true)); -++ } -++ } -++ if (ANNOTATIONS && itanns != 0) { -++ for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { -++ v = readAnnotationTarget(context, v); -++ v = readAnnotationValues(v + 2, c, true, -++ fv.visitTypeAnnotation(context.typeRef, -++ context.typePath, readUTF8(v, c), false)); -++ } -++ } -++ -++ // visits the field attributes -++ while (attributes != null) { -++ Attribute attr = attributes.next; -++ attributes.next = null; -++ fv.visitAttribute(attributes); -++ attributes = attr; -++ } -++ -++ // visits the end of the field -++ fv.visitEnd(); -++ -++ return u; -++ } -++ -++ /** -++ * Reads a method and makes the given visitor visit it. -++ * -++ * @param classVisitor -++ * the visitor that must visit the method. -++ * @param context -++ * information about the class being parsed. -++ * @param u -++ * the start offset of the method in the class file. -++ * @return the offset of the first byte following the method in the class. -++ */ -++ private int readMethod(final ClassVisitor classVisitor, -++ final Context context, int u) { -++ // reads the method declaration -++ char[] c = context.buffer; -++ context.access = readUnsignedShort(u); -++ context.name = readUTF8(u + 2, c); -++ context.desc = readUTF8(u + 4, c); -++ u += 6; -++ -++ // reads the method attributes -++ int code = 0; -++ int exception = 0; -++ String[] exceptions = null; -++ String signature = null; -++ int methodParameters = 0; -++ int anns = 0; -++ int ianns = 0; -++ int tanns = 0; -++ int itanns = 0; -++ int dann = 0; -++ int mpanns = 0; -++ int impanns = 0; -++ int firstAttribute = u; -++ Attribute attributes = null; -++ -++ for (int i = readUnsignedShort(u); i > 0; --i) { -++ String attrName = readUTF8(u + 2, c); -++ // tests are sorted in decreasing frequency order -++ // (based on frequencies observed on typical classes) -++ if ("Code".equals(attrName)) { -++ if ((context.flags & SKIP_CODE) == 0) { -++ code = u + 8; -++ } -++ } else if ("Exceptions".equals(attrName)) { -++ exceptions = new String[readUnsignedShort(u + 8)]; -++ exception = u + 10; -++ for (int j = 0; j < exceptions.length; ++j) { -++ exceptions[j] = readClass(exception, c); -++ exception += 2; -++ } -++ } else if (SIGNATURES && "Signature".equals(attrName)) { -++ signature = readUTF8(u + 8, c); -++ } else if ("Deprecated".equals(attrName)) { -++ context.access |= Opcodes.ACC_DEPRECATED; -++ } else if (ANNOTATIONS -++ && "RuntimeVisibleAnnotations".equals(attrName)) { -++ anns = u + 8; -++ } else if (ANNOTATIONS -++ && "RuntimeVisibleTypeAnnotations".equals(attrName)) { -++ tanns = u + 8; -++ } else if (ANNOTATIONS && "AnnotationDefault".equals(attrName)) { -++ dann = u + 8; -++ } else if ("Synthetic".equals(attrName)) { -++ context.access |= Opcodes.ACC_SYNTHETIC -++ | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; -++ } else if (ANNOTATIONS -++ && "RuntimeInvisibleAnnotations".equals(attrName)) { -++ ianns = u + 8; -++ } else if (ANNOTATIONS -++ && "RuntimeInvisibleTypeAnnotations".equals(attrName)) { -++ itanns = u + 8; -++ } else if (ANNOTATIONS -++ && "RuntimeVisibleParameterAnnotations".equals(attrName)) { -++ mpanns = u + 8; -++ } else if (ANNOTATIONS -++ && "RuntimeInvisibleParameterAnnotations".equals(attrName)) { -++ impanns = u + 8; -++ } else if ("MethodParameters".equals(attrName)) { -++ methodParameters = u + 8; -++ } else { -++ Attribute attr = readAttribute(context.attrs, attrName, u + 8, -++ readInt(u + 4), c, -1, null); -++ if (attr != null) { -++ attr.next = attributes; -++ attributes = attr; -++ } -++ } -++ u += 6 + readInt(u + 4); -++ } -++ u += 2; -++ -++ // visits the method declaration -++ MethodVisitor mv = classVisitor.visitMethod(context.access, -++ context.name, context.desc, signature, exceptions); -++ if (mv == null) { -++ return u; -++ } -++ -++ /* -++ * if the returned MethodVisitor is in fact a MethodWriter, it means -++ * there is no method adapter between the reader and the writer. If, in -++ * addition, the writer's constant pool was copied from this reader -++ * (mw.cw.cr == this), and the signature and exceptions of the method -++ * have not been changed, then it is possible to skip all visit events -++ * and just copy the original code of the method to the writer (the -++ * access, name and descriptor can have been changed, this is not -++ * important since they are not copied as is from the reader). -++ */ -++ if (WRITER && mv instanceof MethodWriter) { -++ MethodWriter mw = (MethodWriter) mv; -++ if (mw.cw.cr == this && signature == mw.signature) { -++ boolean sameExceptions = false; -++ if (exceptions == null) { -++ sameExceptions = mw.exceptionCount == 0; -++ } else if (exceptions.length == mw.exceptionCount) { -++ sameExceptions = true; -++ for (int j = exceptions.length - 1; j >= 0; --j) { -++ exception -= 2; -++ if (mw.exceptions[j] != readUnsignedShort(exception)) { -++ sameExceptions = false; -++ break; -++ } -++ } -++ } -++ if (sameExceptions) { -++ /* -++ * we do not copy directly the code into MethodWriter to -++ * save a byte array copy operation. The real copy will be -++ * done in ClassWriter.toByteArray(). -++ */ -++ mw.classReaderOffset = firstAttribute; -++ mw.classReaderLength = u - firstAttribute; -++ return u; -++ } -++ } -++ } -++ -++ // visit the method parameters -++ if (methodParameters != 0) { -++ for (int i = b[methodParameters] & 0xFF, v = methodParameters + 1; i > 0; --i, v = v + 4) { -++ mv.visitParameter(readUTF8(v, c), readUnsignedShort(v + 2)); -++ } -++ } -++ -++ // visits the method annotations -++ if (ANNOTATIONS && dann != 0) { -++ AnnotationVisitor dv = mv.visitAnnotationDefault(); -++ readAnnotationValue(dann, c, null, dv); -++ if (dv != null) { -++ dv.visitEnd(); -++ } -++ } -++ if (ANNOTATIONS && anns != 0) { -++ for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) { -++ v = readAnnotationValues(v + 2, c, true, -++ mv.visitAnnotation(readUTF8(v, c), true)); -++ } -++ } -++ if (ANNOTATIONS && ianns != 0) { -++ for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) { -++ v = readAnnotationValues(v + 2, c, true, -++ mv.visitAnnotation(readUTF8(v, c), false)); -++ } -++ } -++ if (ANNOTATIONS && tanns != 0) { -++ for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { -++ v = readAnnotationTarget(context, v); -++ v = readAnnotationValues(v + 2, c, true, -++ mv.visitTypeAnnotation(context.typeRef, -++ context.typePath, readUTF8(v, c), true)); -++ } -++ } -++ if (ANNOTATIONS && itanns != 0) { -++ for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { -++ v = readAnnotationTarget(context, v); -++ v = readAnnotationValues(v + 2, c, true, -++ mv.visitTypeAnnotation(context.typeRef, -++ context.typePath, readUTF8(v, c), false)); -++ } -++ } -++ if (ANNOTATIONS && mpanns != 0) { -++ readParameterAnnotations(mv, context, mpanns, true); -++ } -++ if (ANNOTATIONS && impanns != 0) { -++ readParameterAnnotations(mv, context, impanns, false); -++ } -++ -++ // visits the method attributes -++ while (attributes != null) { -++ Attribute attr = attributes.next; -++ attributes.next = null; -++ mv.visitAttribute(attributes); -++ attributes = attr; -++ } -++ -++ // visits the method code -++ if (code != 0) { -++ mv.visitCode(); -++ readCode(mv, context, code); -++ } -++ -++ // visits the end of the method -++ mv.visitEnd(); -++ -++ return u; -++ } -++ -++ /** -++ * Reads the bytecode of a method and makes the given visitor visit it. -++ * -++ * @param mv -++ * the visitor that must visit the method's code. -++ * @param context -++ * information about the class being parsed. -++ * @param u -++ * the start offset of the code attribute in the class file. -++ */ -++ private void readCode(final MethodVisitor mv, final Context context, int u) { -++ // reads the header -++ byte[] b = this.b; -++ char[] c = context.buffer; -++ int maxStack = readUnsignedShort(u); -++ int maxLocals = readUnsignedShort(u + 2); -++ int codeLength = readInt(u + 4); -++ u += 8; -++ -++ // reads the bytecode to find the labels -++ int codeStart = u; -++ int codeEnd = u + codeLength; -++ Label[] labels = context.labels = new Label[codeLength + 2]; -++ readLabel(codeLength + 1, labels); -++ while (u < codeEnd) { -++ int offset = u - codeStart; -++ int opcode = b[u] & 0xFF; -++ switch (ClassWriter.TYPE[opcode]) { -++ case ClassWriter.NOARG_INSN: -++ case ClassWriter.IMPLVAR_INSN: -++ u += 1; -++ break; -++ case ClassWriter.LABEL_INSN: -++ readLabel(offset + readShort(u + 1), labels); -++ u += 3; -++ break; -++ case ClassWriter.LABELW_INSN: -++ readLabel(offset + readInt(u + 1), labels); -++ u += 5; -++ break; -++ case ClassWriter.WIDE_INSN: -++ opcode = b[u + 1] & 0xFF; -++ if (opcode == Opcodes.IINC) { -++ u += 6; -++ } else { -++ u += 4; -++ } -++ break; -++ case ClassWriter.TABL_INSN: -++ // skips 0 to 3 padding bytes -++ u = u + 4 - (offset & 3); -++ // reads instruction -++ readLabel(offset + readInt(u), labels); -++ for (int i = readInt(u + 8) - readInt(u + 4) + 1; i > 0; --i) { -++ readLabel(offset + readInt(u + 12), labels); -++ u += 4; -++ } -++ u += 12; -++ break; -++ case ClassWriter.LOOK_INSN: -++ // skips 0 to 3 padding bytes -++ u = u + 4 - (offset & 3); -++ // reads instruction -++ readLabel(offset + readInt(u), labels); -++ for (int i = readInt(u + 4); i > 0; --i) { -++ readLabel(offset + readInt(u + 12), labels); -++ u += 8; -++ } -++ u += 8; -++ break; -++ case ClassWriter.VAR_INSN: -++ case ClassWriter.SBYTE_INSN: -++ case ClassWriter.LDC_INSN: -++ u += 2; -++ break; -++ case ClassWriter.SHORT_INSN: -++ case ClassWriter.LDCW_INSN: -++ case ClassWriter.FIELDORMETH_INSN: -++ case ClassWriter.TYPE_INSN: -++ case ClassWriter.IINC_INSN: -++ u += 3; -++ break; -++ case ClassWriter.ITFMETH_INSN: -++ case ClassWriter.INDYMETH_INSN: -++ u += 5; -++ break; -++ // case MANA_INSN: -++ default: -++ u += 4; -++ break; -++ } -++ } -++ -++ // reads the try catch entries to find the labels, and also visits them -++ for (int i = readUnsignedShort(u); i > 0; --i) { -++ Label start = readLabel(readUnsignedShort(u + 2), labels); -++ Label end = readLabel(readUnsignedShort(u + 4), labels); -++ Label handler = readLabel(readUnsignedShort(u + 6), labels); -++ String type = readUTF8(items[readUnsignedShort(u + 8)], c); -++ mv.visitTryCatchBlock(start, end, handler, type); -++ u += 8; -++ } -++ u += 2; -++ -++ // reads the code attributes -++ int[] tanns = null; // start index of each visible type annotation -++ int[] itanns = null; // start index of each invisible type annotation -++ int tann = 0; // current index in tanns array -++ int itann = 0; // current index in itanns array -++ int ntoff = -1; // next visible type annotation code offset -++ int nitoff = -1; // next invisible type annotation code offset -++ int varTable = 0; -++ int varTypeTable = 0; -++ boolean zip = true; -++ boolean unzip = (context.flags & EXPAND_FRAMES) != 0; -++ int stackMap = 0; -++ int stackMapSize = 0; -++ int frameCount = 0; -++ Context frame = null; -++ Attribute attributes = null; -++ -++ for (int i = readUnsignedShort(u); i > 0; --i) { -++ String attrName = readUTF8(u + 2, c); -++ if ("LocalVariableTable".equals(attrName)) { -++ if ((context.flags & SKIP_DEBUG) == 0) { -++ varTable = u + 8; -++ for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) { -++ int label = readUnsignedShort(v + 10); -++ if (labels[label] == null) { -++ readLabel(label, labels).status |= Label.DEBUG; -++ } -++ label += readUnsignedShort(v + 12); -++ if (labels[label] == null) { -++ readLabel(label, labels).status |= Label.DEBUG; -++ } -++ v += 10; -++ } -++ } -++ } else if ("LocalVariableTypeTable".equals(attrName)) { -++ varTypeTable = u + 8; -++ } else if ("LineNumberTable".equals(attrName)) { -++ if ((context.flags & SKIP_DEBUG) == 0) { -++ for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) { -++ int label = readUnsignedShort(v + 10); -++ if (labels[label] == null) { -++ readLabel(label, labels).status |= Label.DEBUG; -++ } -++ Label l = labels[label]; -++ while (l.line > 0) { -++ if (l.next == null) { -++ l.next = new Label(); -++ } -++ l = l.next; -++ } -++ l.line = readUnsignedShort(v + 12); -++ v += 4; -++ } -++ } -++ } else if (ANNOTATIONS -++ && "RuntimeVisibleTypeAnnotations".equals(attrName)) { -++ tanns = readTypeAnnotations(mv, context, u + 8, true); -++ ntoff = tanns.length == 0 || readByte(tanns[0]) < 0x43 ? -1 -++ : readUnsignedShort(tanns[0] + 1); -++ } else if (ANNOTATIONS -++ && "RuntimeInvisibleTypeAnnotations".equals(attrName)) { -++ itanns = readTypeAnnotations(mv, context, u + 8, false); -++ nitoff = itanns.length == 0 || readByte(itanns[0]) < 0x43 ? -1 -++ : readUnsignedShort(itanns[0] + 1); -++ } else if (FRAMES && "StackMapTable".equals(attrName)) { -++ if ((context.flags & SKIP_FRAMES) == 0) { -++ stackMap = u + 10; -++ stackMapSize = readInt(u + 4); -++ frameCount = readUnsignedShort(u + 8); -++ } -++ /* -++ * here we do not extract the labels corresponding to the -++ * attribute content. This would require a full parsing of the -++ * attribute, which would need to be repeated in the second -++ * phase (see below). Instead the content of the attribute is -++ * read one frame at a time (i.e. after a frame has been -++ * visited, the next frame is read), and the labels it contains -++ * are also extracted one frame at a time. Thanks to the -++ * ordering of frames, having only a "one frame lookahead" is -++ * not a problem, i.e. it is not possible to see an offset -++ * smaller than the offset of the current insn and for which no -++ * Label exist. -++ */ -++ /* -++ * This is not true for UNINITIALIZED type offsets. We solve -++ * this by parsing the stack map table without a full decoding -++ * (see below). -++ */ -++ } else if (FRAMES && "StackMap".equals(attrName)) { -++ if ((context.flags & SKIP_FRAMES) == 0) { -++ zip = false; -++ stackMap = u + 10; -++ stackMapSize = readInt(u + 4); -++ frameCount = readUnsignedShort(u + 8); -++ } -++ /* -++ * IMPORTANT! here we assume that the frames are ordered, as in -++ * the StackMapTable attribute, although this is not guaranteed -++ * by the attribute format. -++ */ -++ } else { -++ for (int j = 0; j < context.attrs.length; ++j) { -++ if (context.attrs[j].type.equals(attrName)) { -++ Attribute attr = context.attrs[j].read(this, u + 8, -++ readInt(u + 4), c, codeStart - 8, labels); -++ if (attr != null) { -++ attr.next = attributes; -++ attributes = attr; -++ } -++ } -++ } -++ } -++ u += 6 + readInt(u + 4); -++ } -++ u += 2; -++ -++ // generates the first (implicit) stack map frame -++ if (FRAMES && stackMap != 0) { -++ /* -++ * for the first explicit frame the offset is not offset_delta + 1 -++ * but only offset_delta; setting the implicit frame offset to -1 -++ * allow the use of the "offset_delta + 1" rule in all cases -++ */ -++ frame = context; -++ frame.offset = -1; -++ frame.mode = 0; -++ frame.localCount = 0; -++ frame.localDiff = 0; -++ frame.stackCount = 0; -++ frame.local = new Object[maxLocals]; -++ frame.stack = new Object[maxStack]; -++ if (unzip) { -++ getImplicitFrame(context); -++ } -++ /* -++ * Finds labels for UNINITIALIZED frame types. Instead of decoding -++ * each element of the stack map table, we look for 3 consecutive -++ * bytes that "look like" an UNINITIALIZED type (tag 8, offset -++ * within code bounds, NEW instruction at this offset). We may find -++ * false positives (i.e. not real UNINITIALIZED types), but this -++ * should be rare, and the only consequence will be the creation of -++ * an unneeded label. This is better than creating a label for each -++ * NEW instruction, and faster than fully decoding the whole stack -++ * map table. -++ */ -++ for (int i = stackMap; i < stackMap + stackMapSize - 2; ++i) { -++ if (b[i] == 8) { // UNINITIALIZED FRAME TYPE -++ int v = readUnsignedShort(i + 1); -++ if (v >= 0 && v < codeLength) { -++ if ((b[codeStart + v] & 0xFF) == Opcodes.NEW) { -++ readLabel(v, labels); -++ } -++ } -++ } -++ } -++ } -++ -++ // visits the instructions -++ u = codeStart; -++ while (u < codeEnd) { -++ int offset = u - codeStart; -++ -++ // visits the label and line number for this offset, if any -++ Label l = labels[offset]; -++ if (l != null) { -++ Label next = l.next; -++ l.next = null; -++ mv.visitLabel(l); -++ if ((context.flags & SKIP_DEBUG) == 0 && l.line > 0) { -++ mv.visitLineNumber(l.line, l); -++ while (next != null) { -++ mv.visitLineNumber(next.line, l); -++ next = next.next; -++ } -++ } -++ } -++ -++ // visits the frame for this offset, if any -++ while (FRAMES && frame != null -++ && (frame.offset == offset || frame.offset == -1)) { -++ // if there is a frame for this offset, makes the visitor visit -++ // it, and reads the next frame if there is one. -++ if (frame.offset != -1) { -++ if (!zip || unzip) { -++ mv.visitFrame(Opcodes.F_NEW, frame.localCount, -++ frame.local, frame.stackCount, frame.stack); -++ } else { -++ mv.visitFrame(frame.mode, frame.localDiff, frame.local, -++ frame.stackCount, frame.stack); -++ } -++ } -++ if (frameCount > 0) { -++ stackMap = readFrame(stackMap, zip, unzip, frame); -++ --frameCount; -++ } else { -++ frame = null; -++ } -++ } -++ -++ // visits the instruction at this offset -++ int opcode = b[u] & 0xFF; -++ switch (ClassWriter.TYPE[opcode]) { -++ case ClassWriter.NOARG_INSN: -++ mv.visitInsn(opcode); -++ u += 1; -++ break; -++ case ClassWriter.IMPLVAR_INSN: -++ if (opcode > Opcodes.ISTORE) { -++ opcode -= 59; // ISTORE_0 -++ mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), -++ opcode & 0x3); -++ } else { -++ opcode -= 26; // ILOAD_0 -++ mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3); -++ } -++ u += 1; -++ break; -++ case ClassWriter.LABEL_INSN: -++ mv.visitJumpInsn(opcode, labels[offset + readShort(u + 1)]); -++ u += 3; -++ break; -++ case ClassWriter.LABELW_INSN: -++ mv.visitJumpInsn(opcode - 33, labels[offset + readInt(u + 1)]); -++ u += 5; -++ break; -++ case ClassWriter.WIDE_INSN: -++ opcode = b[u + 1] & 0xFF; -++ if (opcode == Opcodes.IINC) { -++ mv.visitIincInsn(readUnsignedShort(u + 2), readShort(u + 4)); -++ u += 6; -++ } else { -++ mv.visitVarInsn(opcode, readUnsignedShort(u + 2)); -++ u += 4; -++ } -++ break; -++ case ClassWriter.TABL_INSN: { -++ // skips 0 to 3 padding bytes -++ u = u + 4 - (offset & 3); -++ // reads instruction -++ int label = offset + readInt(u); -++ int min = readInt(u + 4); -++ int max = readInt(u + 8); -++ Label[] table = new Label[max - min + 1]; -++ u += 12; -++ for (int i = 0; i < table.length; ++i) { -++ table[i] = labels[offset + readInt(u)]; -++ u += 4; -++ } -++ mv.visitTableSwitchInsn(min, max, labels[label], table); -++ break; -++ } -++ case ClassWriter.LOOK_INSN: { -++ // skips 0 to 3 padding bytes -++ u = u + 4 - (offset & 3); -++ // reads instruction -++ int label = offset + readInt(u); -++ int len = readInt(u + 4); -++ int[] keys = new int[len]; -++ Label[] values = new Label[len]; -++ u += 8; -++ for (int i = 0; i < len; ++i) { -++ keys[i] = readInt(u); -++ values[i] = labels[offset + readInt(u + 4)]; -++ u += 8; -++ } -++ mv.visitLookupSwitchInsn(labels[label], keys, values); -++ break; -++ } -++ case ClassWriter.VAR_INSN: -++ mv.visitVarInsn(opcode, b[u + 1] & 0xFF); -++ u += 2; -++ break; -++ case ClassWriter.SBYTE_INSN: -++ mv.visitIntInsn(opcode, b[u + 1]); -++ u += 2; -++ break; -++ case ClassWriter.SHORT_INSN: -++ mv.visitIntInsn(opcode, readShort(u + 1)); -++ u += 3; -++ break; -++ case ClassWriter.LDC_INSN: -++ mv.visitLdcInsn(readConst(b[u + 1] & 0xFF, c)); -++ u += 2; -++ break; -++ case ClassWriter.LDCW_INSN: -++ mv.visitLdcInsn(readConst(readUnsignedShort(u + 1), c)); -++ u += 3; -++ break; -++ case ClassWriter.FIELDORMETH_INSN: -++ case ClassWriter.ITFMETH_INSN: { -++ int cpIndex = items[readUnsignedShort(u + 1)]; -++ boolean itf = b[cpIndex - 1] == ClassWriter.IMETH; -++ String iowner = readClass(cpIndex, c); -++ cpIndex = items[readUnsignedShort(cpIndex + 2)]; -++ String iname = readUTF8(cpIndex, c); -++ String idesc = readUTF8(cpIndex + 2, c); -++ if (opcode < Opcodes.INVOKEVIRTUAL) { -++ mv.visitFieldInsn(opcode, iowner, iname, idesc); -++ } else { -++ mv.visitMethodInsn(opcode, iowner, iname, idesc, itf); -++ } -++ if (opcode == Opcodes.INVOKEINTERFACE) { -++ u += 5; -++ } else { -++ u += 3; -++ } -++ break; -++ } -++ case ClassWriter.INDYMETH_INSN: { -++ int cpIndex = items[readUnsignedShort(u + 1)]; -++ int bsmIndex = context.bootstrapMethods[readUnsignedShort(cpIndex)]; -++ Handle bsm = (Handle) readConst(readUnsignedShort(bsmIndex), c); -++ int bsmArgCount = readUnsignedShort(bsmIndex + 2); -++ Object[] bsmArgs = new Object[bsmArgCount]; -++ bsmIndex += 4; -++ for (int i = 0; i < bsmArgCount; i++) { -++ bsmArgs[i] = readConst(readUnsignedShort(bsmIndex), c); -++ bsmIndex += 2; -++ } -++ cpIndex = items[readUnsignedShort(cpIndex + 2)]; -++ String iname = readUTF8(cpIndex, c); -++ String idesc = readUTF8(cpIndex + 2, c); -++ mv.visitInvokeDynamicInsn(iname, idesc, bsm, bsmArgs); -++ u += 5; -++ break; -++ } -++ case ClassWriter.TYPE_INSN: -++ mv.visitTypeInsn(opcode, readClass(u + 1, c)); -++ u += 3; -++ break; -++ case ClassWriter.IINC_INSN: -++ mv.visitIincInsn(b[u + 1] & 0xFF, b[u + 2]); -++ u += 3; -++ break; -++ // case MANA_INSN: -++ default: -++ mv.visitMultiANewArrayInsn(readClass(u + 1, c), b[u + 3] & 0xFF); -++ u += 4; -++ break; -++ } -++ -++ // visit the instruction annotations, if any -++ while (tanns != null && tann < tanns.length && ntoff <= offset) { -++ if (ntoff == offset) { -++ int v = readAnnotationTarget(context, tanns[tann]); -++ readAnnotationValues(v + 2, c, true, -++ mv.visitInsnAnnotation(context.typeRef, -++ context.typePath, readUTF8(v, c), true)); -++ } -++ ntoff = ++tann >= tanns.length || readByte(tanns[tann]) < 0x43 ? -1 -++ : readUnsignedShort(tanns[tann] + 1); -++ } -++ while (itanns != null && itann < itanns.length && nitoff <= offset) { -++ if (nitoff == offset) { -++ int v = readAnnotationTarget(context, itanns[itann]); -++ readAnnotationValues(v + 2, c, true, -++ mv.visitInsnAnnotation(context.typeRef, -++ context.typePath, readUTF8(v, c), false)); -++ } -++ nitoff = ++itann >= itanns.length -++ || readByte(itanns[itann]) < 0x43 ? -1 -++ : readUnsignedShort(itanns[itann] + 1); -++ } -++ } -++ if (labels[codeLength] != null) { -++ mv.visitLabel(labels[codeLength]); -++ } -++ -++ // visits the local variable tables -++ if ((context.flags & SKIP_DEBUG) == 0 && varTable != 0) { -++ int[] typeTable = null; -++ if (varTypeTable != 0) { -++ u = varTypeTable + 2; -++ typeTable = new int[readUnsignedShort(varTypeTable) * 3]; -++ for (int i = typeTable.length; i > 0;) { -++ typeTable[--i] = u + 6; // signature -++ typeTable[--i] = readUnsignedShort(u + 8); // index -++ typeTable[--i] = readUnsignedShort(u); // start -++ u += 10; -++ } -++ } -++ u = varTable + 2; -++ for (int i = readUnsignedShort(varTable); i > 0; --i) { -++ int start = readUnsignedShort(u); -++ int length = readUnsignedShort(u + 2); -++ int index = readUnsignedShort(u + 8); -++ String vsignature = null; -++ if (typeTable != null) { -++ for (int j = 0; j < typeTable.length; j += 3) { -++ if (typeTable[j] == start && typeTable[j + 1] == index) { -++ vsignature = readUTF8(typeTable[j + 2], c); -++ break; -++ } -++ } -++ } -++ mv.visitLocalVariable(readUTF8(u + 4, c), readUTF8(u + 6, c), -++ vsignature, labels[start], labels[start + length], -++ index); -++ u += 10; -++ } -++ } -++ -++ // visits the local variables type annotations -++ if (tanns != null) { -++ for (int i = 0; i < tanns.length; ++i) { -++ if ((readByte(tanns[i]) >> 1) == (0x40 >> 1)) { -++ int v = readAnnotationTarget(context, tanns[i]); -++ v = readAnnotationValues(v + 2, c, true, -++ mv.visitLocalVariableAnnotation(context.typeRef, -++ context.typePath, context.start, -++ context.end, context.index, readUTF8(v, c), -++ true)); -++ } -++ } -++ } -++ if (itanns != null) { -++ for (int i = 0; i < itanns.length; ++i) { -++ if ((readByte(itanns[i]) >> 1) == (0x40 >> 1)) { -++ int v = readAnnotationTarget(context, itanns[i]); -++ v = readAnnotationValues(v + 2, c, true, -++ mv.visitLocalVariableAnnotation(context.typeRef, -++ context.typePath, context.start, -++ context.end, context.index, readUTF8(v, c), -++ false)); -++ } -++ } -++ } -++ -++ // visits the code attributes -++ while (attributes != null) { -++ Attribute attr = attributes.next; -++ attributes.next = null; -++ mv.visitAttribute(attributes); -++ attributes = attr; -++ } -++ -++ // visits the max stack and max locals values -++ mv.visitMaxs(maxStack, maxLocals); -++ } -++ -++ /** -++ * Parses a type annotation table to find the labels, and to visit the try -++ * catch block annotations. -++ * -++ * @param u -++ * the start offset of a type annotation table. -++ * @param mv -++ * the method visitor to be used to visit the try catch block -++ * annotations. -++ * @param context -++ * information about the class being parsed. -++ * @param visible -++ * if the type annotation table to parse contains runtime visible -++ * annotations. -++ * @return the start offset of each type annotation in the parsed table. -++ */ -++ private int[] readTypeAnnotations(final MethodVisitor mv, -++ final Context context, int u, boolean visible) { -++ char[] c = context.buffer; -++ int[] offsets = new int[readUnsignedShort(u)]; -++ u += 2; -++ for (int i = 0; i < offsets.length; ++i) { -++ offsets[i] = u; -++ int target = readInt(u); -++ switch (target >>> 24) { -++ case 0x00: // CLASS_TYPE_PARAMETER -++ case 0x01: // METHOD_TYPE_PARAMETER -++ case 0x16: // METHOD_FORMAL_PARAMETER -++ u += 2; -++ break; -++ case 0x13: // FIELD -++ case 0x14: // METHOD_RETURN -++ case 0x15: // METHOD_RECEIVER -++ u += 1; -++ break; -++ case 0x40: // LOCAL_VARIABLE -++ case 0x41: // RESOURCE_VARIABLE -++ for (int j = readUnsignedShort(u + 1); j > 0; --j) { -++ int start = readUnsignedShort(u + 3); -++ int length = readUnsignedShort(u + 5); -++ readLabel(start, context.labels); -++ readLabel(start + length, context.labels); -++ u += 6; -++ } -++ u += 3; -++ break; -++ case 0x47: // CAST -++ case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT -++ case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT -++ case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT -++ case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT -++ u += 4; -++ break; -++ // case 0x10: // CLASS_EXTENDS -++ // case 0x11: // CLASS_TYPE_PARAMETER_BOUND -++ // case 0x12: // METHOD_TYPE_PARAMETER_BOUND -++ // case 0x17: // THROWS -++ // case 0x42: // EXCEPTION_PARAMETER -++ // case 0x43: // INSTANCEOF -++ // case 0x44: // NEW -++ // case 0x45: // CONSTRUCTOR_REFERENCE -++ // case 0x46: // METHOD_REFERENCE -++ default: -++ u += 3; -++ break; -++ } -++ int pathLength = readByte(u); -++ if ((target >>> 24) == 0x42) { -++ TypePath path = pathLength == 0 ? null : new TypePath(b, u); -++ u += 1 + 2 * pathLength; -++ u = readAnnotationValues(u + 2, c, true, -++ mv.visitTryCatchAnnotation(target, path, -++ readUTF8(u, c), visible)); -++ } else { -++ u = readAnnotationValues(u + 3 + 2 * pathLength, c, true, null); -++ } -++ } -++ return offsets; -++ } -++ -++ /** -++ * Parses the header of a type annotation to extract its target_type and -++ * target_path (the result is stored in the given context), and returns the -++ * start offset of the rest of the type_annotation structure (i.e. the -++ * offset to the type_index field, which is followed by -++ * num_element_value_pairs and then the name,value pairs). -++ * -++ * @param context -++ * information about the class being parsed. This is where the -++ * extracted target_type and target_path must be stored. -++ * @param u -++ * the start offset of a type_annotation structure. -++ * @return the start offset of the rest of the type_annotation structure. -++ */ -++ private int readAnnotationTarget(final Context context, int u) { -++ int target = readInt(u); -++ switch (target >>> 24) { -++ case 0x00: // CLASS_TYPE_PARAMETER -++ case 0x01: // METHOD_TYPE_PARAMETER -++ case 0x16: // METHOD_FORMAL_PARAMETER -++ target &= 0xFFFF0000; -++ u += 2; -++ break; -++ case 0x13: // FIELD -++ case 0x14: // METHOD_RETURN -++ case 0x15: // METHOD_RECEIVER -++ target &= 0xFF000000; -++ u += 1; -++ break; -++ case 0x40: // LOCAL_VARIABLE -++ case 0x41: { // RESOURCE_VARIABLE -++ target &= 0xFF000000; -++ int n = readUnsignedShort(u + 1); -++ context.start = new Label[n]; -++ context.end = new Label[n]; -++ context.index = new int[n]; -++ u += 3; -++ for (int i = 0; i < n; ++i) { -++ int start = readUnsignedShort(u); -++ int length = readUnsignedShort(u + 2); -++ context.start[i] = readLabel(start, context.labels); -++ context.end[i] = readLabel(start + length, context.labels); -++ context.index[i] = readUnsignedShort(u + 4); -++ u += 6; -++ } -++ break; -++ } -++ case 0x47: // CAST -++ case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT -++ case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT -++ case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT -++ case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT -++ target &= 0xFF0000FF; -++ u += 4; -++ break; -++ // case 0x10: // CLASS_EXTENDS -++ // case 0x11: // CLASS_TYPE_PARAMETER_BOUND -++ // case 0x12: // METHOD_TYPE_PARAMETER_BOUND -++ // case 0x17: // THROWS -++ // case 0x42: // EXCEPTION_PARAMETER -++ // case 0x43: // INSTANCEOF -++ // case 0x44: // NEW -++ // case 0x45: // CONSTRUCTOR_REFERENCE -++ // case 0x46: // METHOD_REFERENCE -++ default: -++ target &= (target >>> 24) < 0x43 ? 0xFFFFFF00 : 0xFF000000; -++ u += 3; -++ break; -++ } -++ int pathLength = readByte(u); -++ context.typeRef = target; -++ context.typePath = pathLength == 0 ? null : new TypePath(b, u); -++ return u + 1 + 2 * pathLength; -++ } -++ -++ /** -++ * Reads parameter annotations and makes the given visitor visit them. -++ * -++ * @param mv -++ * the visitor that must visit the annotations. -++ * @param context -++ * information about the class being parsed. -++ * @param v -++ * start offset in {@link #b b} of the annotations to be read. -++ * @param visible -++ * true if the annotations to be read are visible at -++ * runtime. -++ */ -++ private void readParameterAnnotations(final MethodVisitor mv, -++ final Context context, int v, final boolean visible) { -++ int i; -++ int n = b[v++] & 0xFF; -++ // workaround for a bug in javac (javac compiler generates a parameter -++ // annotation array whose size is equal to the number of parameters in -++ // the Java source file, while it should generate an array whose size is -++ // equal to the number of parameters in the method descriptor - which -++ // includes the synthetic parameters added by the compiler). This work- -++ // around supposes that the synthetic parameters are the first ones. -++ int synthetics = Type.getArgumentTypes(context.desc).length - n; -++ AnnotationVisitor av; -++ for (i = 0; i < synthetics; ++i) { -++ // virtual annotation to detect synthetic parameters in MethodWriter -++ av = mv.visitParameterAnnotation(i, "Ljava/lang/Synthetic;", false); -++ if (av != null) { -++ av.visitEnd(); -++ } -++ } -++ char[] c = context.buffer; -++ for (; i < n + synthetics; ++i) { -++ int j = readUnsignedShort(v); -++ v += 2; -++ for (; j > 0; --j) { -++ av = mv.visitParameterAnnotation(i, readUTF8(v, c), visible); -++ v = readAnnotationValues(v + 2, c, true, av); -++ } -++ } -++ } -++ -++ /** -++ * Reads the values of an annotation and makes the given visitor visit them. -++ * -++ * @param v -++ * the start offset in {@link #b b} of the values to be read -++ * (including the unsigned short that gives the number of -++ * values). -++ * @param buf -++ * buffer to be used to call {@link #readUTF8 readUTF8}, -++ * {@link #readClass(int,char[]) readClass} or {@link #readConst -++ * readConst}. -++ * @param named -++ * if the annotation values are named or not. -++ * @param av -++ * the visitor that must visit the values. -++ * @return the end offset of the annotation values. -++ */ -++ private int readAnnotationValues(int v, final char[] buf, -++ final boolean named, final AnnotationVisitor av) { -++ int i = readUnsignedShort(v); -++ v += 2; -++ if (named) { -++ for (; i > 0; --i) { -++ v = readAnnotationValue(v + 2, buf, readUTF8(v, buf), av); -++ } -++ } else { -++ for (; i > 0; --i) { -++ v = readAnnotationValue(v, buf, null, av); -++ } -++ } -++ if (av != null) { -++ av.visitEnd(); -++ } -++ return v; -++ } -++ -++ /** -++ * Reads a value of an annotation and makes the given visitor visit it. -++ * -++ * @param v -++ * the start offset in {@link #b b} of the value to be read -++ * (not including the value name constant pool index). -++ * @param buf -++ * buffer to be used to call {@link #readUTF8 readUTF8}, -++ * {@link #readClass(int,char[]) readClass} or {@link #readConst -++ * readConst}. -++ * @param name -++ * the name of the value to be read. -++ * @param av -++ * the visitor that must visit the value. -++ * @return the end offset of the annotation value. -++ */ -++ private int readAnnotationValue(int v, final char[] buf, final String name, -++ final AnnotationVisitor av) { -++ int i; -++ if (av == null) { -++ switch (b[v] & 0xFF) { -++ case 'e': // enum_const_value -++ return v + 5; -++ case '@': // annotation_value -++ return readAnnotationValues(v + 3, buf, true, null); -++ case '[': // array_value -++ return readAnnotationValues(v + 1, buf, false, null); -++ default: -++ return v + 3; -++ } -++ } -++ switch (b[v++] & 0xFF) { -++ case 'I': // pointer to CONSTANT_Integer -++ case 'J': // pointer to CONSTANT_Long -++ case 'F': // pointer to CONSTANT_Float -++ case 'D': // pointer to CONSTANT_Double -++ av.visit(name, readConst(readUnsignedShort(v), buf)); -++ v += 2; -++ break; -++ case 'B': // pointer to CONSTANT_Byte -++ av.visit(name, (byte) readInt(items[readUnsignedShort(v)])); -++ v += 2; -++ break; -++ case 'Z': // pointer to CONSTANT_Boolean -++ av.visit(name, -++ readInt(items[readUnsignedShort(v)]) == 0 ? Boolean.FALSE -++ : Boolean.TRUE); -++ v += 2; -++ break; -++ case 'S': // pointer to CONSTANT_Short -++ av.visit(name, (short) readInt(items[readUnsignedShort(v)])); -++ v += 2; -++ break; -++ case 'C': // pointer to CONSTANT_Char -++ av.visit(name, (char) readInt(items[readUnsignedShort(v)])); -++ v += 2; -++ break; -++ case 's': // pointer to CONSTANT_Utf8 -++ av.visit(name, readUTF8(v, buf)); -++ v += 2; -++ break; -++ case 'e': // enum_const_value -++ av.visitEnum(name, readUTF8(v, buf), readUTF8(v + 2, buf)); -++ v += 4; -++ break; -++ case 'c': // class_info -++ av.visit(name, Type.getType(readUTF8(v, buf))); -++ v += 2; -++ break; -++ case '@': // annotation_value -++ v = readAnnotationValues(v + 2, buf, true, -++ av.visitAnnotation(name, readUTF8(v, buf))); -++ break; -++ case '[': // array_value -++ int size = readUnsignedShort(v); -++ v += 2; -++ if (size == 0) { -++ return readAnnotationValues(v - 2, buf, false, -++ av.visitArray(name)); -++ } -++ switch (this.b[v++] & 0xFF) { -++ case 'B': -++ byte[] bv = new byte[size]; -++ for (i = 0; i < size; i++) { -++ bv[i] = (byte) readInt(items[readUnsignedShort(v)]); -++ v += 3; -++ } -++ av.visit(name, bv); -++ --v; -++ break; -++ case 'Z': -++ boolean[] zv = new boolean[size]; -++ for (i = 0; i < size; i++) { -++ zv[i] = readInt(items[readUnsignedShort(v)]) != 0; -++ v += 3; -++ } -++ av.visit(name, zv); -++ --v; -++ break; -++ case 'S': -++ short[] sv = new short[size]; -++ for (i = 0; i < size; i++) { -++ sv[i] = (short) readInt(items[readUnsignedShort(v)]); -++ v += 3; -++ } -++ av.visit(name, sv); -++ --v; -++ break; -++ case 'C': -++ char[] cv = new char[size]; -++ for (i = 0; i < size; i++) { -++ cv[i] = (char) readInt(items[readUnsignedShort(v)]); -++ v += 3; -++ } -++ av.visit(name, cv); -++ --v; -++ break; -++ case 'I': -++ int[] iv = new int[size]; -++ for (i = 0; i < size; i++) { -++ iv[i] = readInt(items[readUnsignedShort(v)]); -++ v += 3; -++ } -++ av.visit(name, iv); -++ --v; -++ break; -++ case 'J': -++ long[] lv = new long[size]; -++ for (i = 0; i < size; i++) { -++ lv[i] = readLong(items[readUnsignedShort(v)]); -++ v += 3; -++ } -++ av.visit(name, lv); -++ --v; -++ break; -++ case 'F': -++ float[] fv = new float[size]; -++ for (i = 0; i < size; i++) { -++ fv[i] = Float -++ .intBitsToFloat(readInt(items[readUnsignedShort(v)])); -++ v += 3; -++ } -++ av.visit(name, fv); -++ --v; -++ break; -++ case 'D': -++ double[] dv = new double[size]; -++ for (i = 0; i < size; i++) { -++ dv[i] = Double -++ .longBitsToDouble(readLong(items[readUnsignedShort(v)])); -++ v += 3; -++ } -++ av.visit(name, dv); -++ --v; -++ break; -++ default: -++ v = readAnnotationValues(v - 3, buf, false, av.visitArray(name)); -++ } -++ } -++ return v; -++ } -++ -++ /** -++ * Computes the implicit frame of the method currently being parsed (as -++ * defined in the given {@link Context}) and stores it in the given context. -++ * -++ * @param frame -++ * information about the class being parsed. -++ */ -++ private void getImplicitFrame(final Context frame) { -++ String desc = frame.desc; -++ Object[] locals = frame.local; -++ int local = 0; -++ if ((frame.access & Opcodes.ACC_STATIC) == 0) { -++ if ("".equals(frame.name)) { -++ locals[local++] = Opcodes.UNINITIALIZED_THIS; -++ } else { -++ locals[local++] = readClass(header + 2, frame.buffer); -++ } -++ } -++ int i = 1; -++ loop: while (true) { -++ int j = i; -++ switch (desc.charAt(i++)) { -++ case 'Z': -++ case 'C': -++ case 'B': -++ case 'S': -++ case 'I': -++ locals[local++] = Opcodes.INTEGER; -++ break; -++ case 'F': -++ locals[local++] = Opcodes.FLOAT; -++ break; -++ case 'J': -++ locals[local++] = Opcodes.LONG; -++ break; -++ case 'D': -++ locals[local++] = Opcodes.DOUBLE; -++ break; -++ case '[': -++ while (desc.charAt(i) == '[') { -++ ++i; -++ } -++ if (desc.charAt(i) == 'L') { -++ ++i; -++ while (desc.charAt(i) != ';') { -++ ++i; -++ } -++ } -++ locals[local++] = desc.substring(j, ++i); -++ break; -++ case 'L': -++ while (desc.charAt(i) != ';') { -++ ++i; -++ } -++ locals[local++] = desc.substring(j + 1, i++); -++ break; -++ default: -++ break loop; -++ } -++ } -++ frame.localCount = local; -++ } -++ -++ /** -++ * Reads a stack map frame and stores the result in the given -++ * {@link Context} object. -++ * -++ * @param stackMap -++ * the start offset of a stack map frame in the class file. -++ * @param zip -++ * if the stack map frame at stackMap is compressed or not. -++ * @param unzip -++ * if the stack map frame must be uncompressed. -++ * @param frame -++ * where the parsed stack map frame must be stored. -++ * @return the offset of the first byte following the parsed frame. -++ */ -++ private int readFrame(int stackMap, boolean zip, boolean unzip, -++ Context frame) { -++ char[] c = frame.buffer; -++ Label[] labels = frame.labels; -++ int tag; -++ int delta; -++ if (zip) { -++ tag = b[stackMap++] & 0xFF; -++ } else { -++ tag = MethodWriter.FULL_FRAME; -++ frame.offset = -1; -++ } -++ frame.localDiff = 0; -++ if (tag < MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME) { -++ delta = tag; -++ frame.mode = Opcodes.F_SAME; -++ frame.stackCount = 0; -++ } else if (tag < MethodWriter.RESERVED) { -++ delta = tag - MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME; -++ stackMap = readFrameType(frame.stack, 0, stackMap, c, labels); -++ frame.mode = Opcodes.F_SAME1; -++ frame.stackCount = 1; -++ } else { -++ delta = readUnsignedShort(stackMap); -++ stackMap += 2; -++ if (tag == MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { -++ stackMap = readFrameType(frame.stack, 0, stackMap, c, labels); -++ frame.mode = Opcodes.F_SAME1; -++ frame.stackCount = 1; -++ } else if (tag >= MethodWriter.CHOP_FRAME -++ && tag < MethodWriter.SAME_FRAME_EXTENDED) { -++ frame.mode = Opcodes.F_CHOP; -++ frame.localDiff = MethodWriter.SAME_FRAME_EXTENDED - tag; -++ frame.localCount -= frame.localDiff; -++ frame.stackCount = 0; -++ } else if (tag == MethodWriter.SAME_FRAME_EXTENDED) { -++ frame.mode = Opcodes.F_SAME; -++ frame.stackCount = 0; -++ } else if (tag < MethodWriter.FULL_FRAME) { -++ int local = unzip ? frame.localCount : 0; -++ for (int i = tag - MethodWriter.SAME_FRAME_EXTENDED; i > 0; i--) { -++ stackMap = readFrameType(frame.local, local++, stackMap, c, -++ labels); -++ } -++ frame.mode = Opcodes.F_APPEND; -++ frame.localDiff = tag - MethodWriter.SAME_FRAME_EXTENDED; -++ frame.localCount += frame.localDiff; -++ frame.stackCount = 0; -++ } else { // if (tag == FULL_FRAME) { -++ frame.mode = Opcodes.F_FULL; -++ int n = readUnsignedShort(stackMap); -++ stackMap += 2; -++ frame.localDiff = n; -++ frame.localCount = n; -++ for (int local = 0; n > 0; n--) { -++ stackMap = readFrameType(frame.local, local++, stackMap, c, -++ labels); -++ } -++ n = readUnsignedShort(stackMap); -++ stackMap += 2; -++ frame.stackCount = n; -++ for (int stack = 0; n > 0; n--) { -++ stackMap = readFrameType(frame.stack, stack++, stackMap, c, -++ labels); -++ } -++ } -++ } -++ frame.offset += delta + 1; -++ readLabel(frame.offset, labels); -++ return stackMap; -++ } -++ -++ /** -++ * Reads a stack map frame type and stores it at the given index in the -++ * given array. -++ * -++ * @param frame -++ * the array where the parsed type must be stored. -++ * @param index -++ * the index in 'frame' where the parsed type must be stored. -++ * @param v -++ * the start offset of the stack map frame type to read. -++ * @param buf -++ * a buffer to read strings. -++ * @param labels -++ * the labels of the method currently being parsed, indexed by -++ * their offset. If the parsed type is an Uninitialized type, a -++ * new label for the corresponding NEW instruction is stored in -++ * this array if it does not already exist. -++ * @return the offset of the first byte after the parsed type. -++ */ -++ private int readFrameType(final Object[] frame, final int index, int v, -++ final char[] buf, final Label[] labels) { -++ int type = b[v++] & 0xFF; -++ switch (type) { -++ case 0: -++ frame[index] = Opcodes.TOP; -++ break; -++ case 1: -++ frame[index] = Opcodes.INTEGER; -++ break; -++ case 2: -++ frame[index] = Opcodes.FLOAT; -++ break; -++ case 3: -++ frame[index] = Opcodes.DOUBLE; -++ break; -++ case 4: -++ frame[index] = Opcodes.LONG; -++ break; -++ case 5: -++ frame[index] = Opcodes.NULL; -++ break; -++ case 6: -++ frame[index] = Opcodes.UNINITIALIZED_THIS; -++ break; -++ case 7: // Object -++ frame[index] = readClass(v, buf); -++ v += 2; -++ break; -++ default: // Uninitialized -++ frame[index] = readLabel(readUnsignedShort(v), labels); -++ v += 2; -++ } -++ return v; -++ } -++ -++ /** -++ * Returns the label corresponding to the given offset. The default -++ * implementation of this method creates a label for the given offset if it -++ * has not been already created. -++ * -++ * @param offset -++ * a bytecode offset in a method. -++ * @param labels -++ * the already created labels, indexed by their offset. If a -++ * label already exists for offset this method must not create a -++ * new one. Otherwise it must store the new label in this array. -++ * @return a non null Label, which must be equal to labels[offset]. -++ */ -++ protected Label readLabel(int offset, Label[] labels) { -++ if (labels[offset] == null) { -++ labels[offset] = new Label(); -++ } -++ return labels[offset]; -++ } -++ -++ /** -++ * Returns the start index of the attribute_info structure of this class. -++ * -++ * @return the start index of the attribute_info structure of this class. -++ */ -++ private int getAttributes() { -++ // skips the header -++ int u = header + 8 + readUnsignedShort(header + 6) * 2; -++ // skips fields and methods -++ for (int i = readUnsignedShort(u); i > 0; --i) { -++ for (int j = readUnsignedShort(u + 8); j > 0; --j) { -++ u += 6 + readInt(u + 12); -++ } -++ u += 8; -++ } -++ u += 2; -++ for (int i = readUnsignedShort(u); i > 0; --i) { -++ for (int j = readUnsignedShort(u + 8); j > 0; --j) { -++ u += 6 + readInt(u + 12); -++ } -++ u += 8; -++ } -++ // the attribute_info structure starts just after the methods -++ return u + 2; -++ } -++ -++ /** -++ * Reads an attribute in {@link #b b}. -++ * -++ * @param attrs -++ * prototypes of the attributes that must be parsed during the -++ * visit of the class. Any attribute whose type is not equal to -++ * the type of one the prototypes is ignored (i.e. an empty -++ * {@link Attribute} instance is returned). -++ * @param type -++ * the type of the attribute. -++ * @param off -++ * index of the first byte of the attribute's content in -++ * {@link #b b}. The 6 attribute header bytes, containing the -++ * type and the length of the attribute, are not taken into -++ * account here (they have already been read). -++ * @param len -++ * the length of the attribute's content. -++ * @param buf -++ * buffer to be used to call {@link #readUTF8 readUTF8}, -++ * {@link #readClass(int,char[]) readClass} or {@link #readConst -++ * readConst}. -++ * @param codeOff -++ * index of the first byte of code's attribute content in -++ * {@link #b b}, or -1 if the attribute to be read is not a code -++ * attribute. The 6 attribute header bytes, containing the type -++ * and the length of the attribute, are not taken into account -++ * here. -++ * @param labels -++ * the labels of the method's code, or null if the -++ * attribute to be read is not a code attribute. -++ * @return the attribute that has been read, or null to skip this -++ * attribute. -++ */ -++ private Attribute readAttribute(final Attribute[] attrs, final String type, -++ final int off, final int len, final char[] buf, final int codeOff, -++ final Label[] labels) { -++ for (int i = 0; i < attrs.length; ++i) { -++ if (attrs[i].type.equals(type)) { -++ return attrs[i].read(this, off, len, buf, codeOff, labels); -++ } -++ } -++ return new Attribute(type).read(this, off, len, null, -1, null); -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Utility methods: low level parsing -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Returns the number of constant pool items in {@link #b b}. -++ * -++ * @return the number of constant pool items in {@link #b b}. -++ */ -++ public int getItemCount() { -++ return items.length; -++ } -++ -++ /** -++ * Returns the start index of the constant pool item in {@link #b b}, plus -++ * one. This method is intended for {@link Attribute} sub classes, and is -++ * normally not needed by class generators or adapters. -++ * -++ * @param item -++ * the index a constant pool item. -++ * @return the start index of the constant pool item in {@link #b b}, plus -++ * one. -++ */ -++ public int getItem(final int item) { -++ return items[item]; -++ } -++ -++ /** -++ * Returns the maximum length of the strings contained in the constant pool -++ * of the class. -++ * -++ * @return the maximum length of the strings contained in the constant pool -++ * of the class. -++ */ -++ public int getMaxStringLength() { -++ return maxStringLength; -++ } -++ -++ /** -++ * Reads a byte value in {@link #b b}. This method is intended for -++ * {@link Attribute} sub classes, and is normally not needed by class -++ * generators or adapters. -++ * -++ * @param index -++ * the start index of the value to be read in {@link #b b}. -++ * @return the read value. -++ */ -++ public int readByte(final int index) { -++ return b[index] & 0xFF; -++ } -++ -++ /** -++ * Reads an unsigned short value in {@link #b b}. This method is intended -++ * for {@link Attribute} sub classes, and is normally not needed by class -++ * generators or adapters. -++ * -++ * @param index -++ * the start index of the value to be read in {@link #b b}. -++ * @return the read value. -++ */ -++ public int readUnsignedShort(final int index) { -++ byte[] b = this.b; -++ return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF); -++ } -++ -++ /** -++ * Reads a signed short value in {@link #b b}. This method is intended -++ * for {@link Attribute} sub classes, and is normally not needed by class -++ * generators or adapters. -++ * -++ * @param index -++ * the start index of the value to be read in {@link #b b}. -++ * @return the read value. -++ */ -++ public short readShort(final int index) { -++ byte[] b = this.b; -++ return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF)); -++ } -++ -++ /** -++ * Reads a signed int value in {@link #b b}. This method is intended for -++ * {@link Attribute} sub classes, and is normally not needed by class -++ * generators or adapters. -++ * -++ * @param index -++ * the start index of the value to be read in {@link #b b}. -++ * @return the read value. -++ */ -++ public int readInt(final int index) { -++ byte[] b = this.b; -++ return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16) -++ | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF); -++ } -++ -++ /** -++ * Reads a signed long value in {@link #b b}. This method is intended for -++ * {@link Attribute} sub classes, and is normally not needed by class -++ * generators or adapters. -++ * -++ * @param index -++ * the start index of the value to be read in {@link #b b}. -++ * @return the read value. -++ */ -++ public long readLong(final int index) { -++ long l1 = readInt(index); -++ long l0 = readInt(index + 4) & 0xFFFFFFFFL; -++ return (l1 << 32) | l0; -++ } -++ -++ /** -++ * Reads an UTF8 string constant pool item in {@link #b b}. This method -++ * is intended for {@link Attribute} sub classes, and is normally not needed -++ * by class generators or adapters. -++ * -++ * @param index -++ * the start index of an unsigned short value in {@link #b b}, -++ * whose value is the index of an UTF8 constant pool item. -++ * @param buf -++ * buffer to be used to read the item. This buffer must be -++ * sufficiently large. It is not automatically resized. -++ * @return the String corresponding to the specified UTF8 item. -++ */ -++ public String readUTF8(int index, final char[] buf) { -++ int item = readUnsignedShort(index); -++ if (index == 0 || item == 0) { -++ return null; -++ } -++ String s = strings[item]; -++ if (s != null) { -++ return s; -++ } -++ index = items[item]; -++ return strings[item] = readUTF(index + 2, readUnsignedShort(index), buf); -++ } -++ -++ /** -++ * Reads UTF8 string in {@link #b b}. -++ * -++ * @param index -++ * start offset of the UTF8 string to be read. -++ * @param utfLen -++ * length of the UTF8 string to be read. -++ * @param buf -++ * buffer to be used to read the string. This buffer must be -++ * sufficiently large. It is not automatically resized. -++ * @return the String corresponding to the specified UTF8 string. -++ */ -++ private String readUTF(int index, final int utfLen, final char[] buf) { -++ int endIndex = index + utfLen; -++ byte[] b = this.b; -++ int strLen = 0; -++ int c; -++ int st = 0; -++ char cc = 0; -++ while (index < endIndex) { -++ c = b[index++]; -++ switch (st) { -++ case 0: -++ c = c & 0xFF; -++ if (c < 0x80) { // 0xxxxxxx -++ buf[strLen++] = (char) c; -++ } else if (c < 0xE0 && c > 0xBF) { // 110x xxxx 10xx xxxx -++ cc = (char) (c & 0x1F); -++ st = 1; -++ } else { // 1110 xxxx 10xx xxxx 10xx xxxx -++ cc = (char) (c & 0x0F); -++ st = 2; -++ } -++ break; -++ -++ case 1: // byte 2 of 2-byte char or byte 3 of 3-byte char -++ buf[strLen++] = (char) ((cc << 6) | (c & 0x3F)); -++ st = 0; -++ break; -++ -++ case 2: // byte 2 of 3-byte char -++ cc = (char) ((cc << 6) | (c & 0x3F)); -++ st = 1; -++ break; -++ } -++ } -++ return new String(buf, 0, strLen); -++ } -++ -++ /** -++ * Reads a class constant pool item in {@link #b b}. This method is -++ * intended for {@link Attribute} sub classes, and is normally not needed by -++ * class generators or adapters. -++ * -++ * @param index -++ * the start index of an unsigned short value in {@link #b b}, -++ * whose value is the index of a class constant pool item. -++ * @param buf -++ * buffer to be used to read the item. This buffer must be -++ * sufficiently large. It is not automatically resized. -++ * @return the String corresponding to the specified class item. -++ */ -++ public String readClass(final int index, final char[] buf) { -++ // computes the start index of the CONSTANT_Class item in b -++ // and reads the CONSTANT_Utf8 item designated by -++ // the first two bytes of this CONSTANT_Class item -++ return readUTF8(items[readUnsignedShort(index)], buf); -++ } -++ -++ /** -++ * Reads a numeric or string constant pool item in {@link #b b}. This -++ * method is intended for {@link Attribute} sub classes, and is normally not -++ * needed by class generators or adapters. -++ * -++ * @param item -++ * the index of a constant pool item. -++ * @param buf -++ * buffer to be used to read the item. This buffer must be -++ * sufficiently large. It is not automatically resized. -++ * @return the {@link Integer}, {@link Float}, {@link Long}, {@link Double}, -++ * {@link String}, {@link Type} or {@link Handle} corresponding to -++ * the given constant pool item. -++ */ -++ public Object readConst(final int item, final char[] buf) { -++ int index = items[item]; -++ switch (b[index - 1]) { -++ case ClassWriter.INT: -++ return readInt(index); -++ case ClassWriter.FLOAT: -++ return Float.intBitsToFloat(readInt(index)); -++ case ClassWriter.LONG: -++ return readLong(index); -++ case ClassWriter.DOUBLE: -++ return Double.longBitsToDouble(readLong(index)); -++ case ClassWriter.CLASS: -++ return Type.getObjectType(readUTF8(index, buf)); -++ case ClassWriter.STR: -++ return readUTF8(index, buf); -++ case ClassWriter.MTYPE: -++ return Type.getMethodType(readUTF8(index, buf)); -++ default: // case ClassWriter.HANDLE_BASE + [1..9]: -++ int tag = readByte(index); -++ int[] items = this.items; -++ int cpIndex = items[readUnsignedShort(index + 1)]; -++ String owner = readClass(cpIndex, buf); -++ cpIndex = items[readUnsignedShort(cpIndex + 2)]; -++ String name = readUTF8(cpIndex, buf); -++ String desc = readUTF8(cpIndex + 2, buf); -++ return new Handle(tag, owner, name, desc); -++ } -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/ClassVisitor.java b/contrib/asm/src/org/objectweb/asm/ClassVisitor.java -+new file mode 100644 -+index 0000000..107ada0 -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/ClassVisitor.java -+@@ -0,0 +1,320 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * A visitor to visit a Java class. The methods of this class must be called in -++ * the following order: visit [ visitSource ] [ -++ * visitOuterClass ] ( visitAnnotation | -++ * visitTypeAnnotation | visitAttribute )* ( -++ * visitInnerClass | visitField | visitMethod )* -++ * visitEnd. -++ * -++ * @author Eric Bruneton -++ */ -++public abstract class ClassVisitor { -++ -++ /** -++ * The ASM API version implemented by this visitor. The value of this field -++ * must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -++ */ -++ protected final int api; -++ -++ /** -++ * The class visitor to which this visitor must delegate method calls. May -++ * be null. -++ */ -++ protected ClassVisitor cv; -++ -++ /** -++ * Constructs a new {@link ClassVisitor}. -++ * -++ * @param api -++ * the ASM API version implemented by this visitor. Must be one -++ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -++ */ -++ public ClassVisitor(final int api) { -++ this(api, null); -++ } -++ -++ /** -++ * Constructs a new {@link ClassVisitor}. -++ * -++ * @param api -++ * the ASM API version implemented by this visitor. Must be one -++ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -++ * @param cv -++ * the class visitor to which this visitor must delegate method -++ * calls. May be null. -++ */ -++ public ClassVisitor(final int api, final ClassVisitor cv) { -++ if (api != Opcodes.ASM4 && api != Opcodes.ASM5) { -++ throw new IllegalArgumentException(); -++ } -++ this.api = api; -++ this.cv = cv; -++ } -++ -++ /** -++ * Visits the header of the class. -++ * -++ * @param version -++ * the class version. -++ * @param access -++ * the class's access flags (see {@link Opcodes}). This parameter -++ * also indicates if the class is deprecated. -++ * @param name -++ * the internal name of the class (see -++ * {@link Type#getInternalName() getInternalName}). -++ * @param signature -++ * the signature of this class. May be null if the class -++ * is not a generic one, and does not extend or implement generic -++ * classes or interfaces. -++ * @param superName -++ * the internal of name of the super class (see -++ * {@link Type#getInternalName() getInternalName}). For -++ * interfaces, the super class is {@link Object}. May be -++ * null, but only for the {@link Object} class. -++ * @param interfaces -++ * the internal names of the class's interfaces (see -++ * {@link Type#getInternalName() getInternalName}). May be -++ * null. -++ */ -++ public void visit(int version, int access, String name, String signature, -++ String superName, String[] interfaces) { -++ if (cv != null) { -++ cv.visit(version, access, name, signature, superName, interfaces); -++ } -++ } -++ -++ /** -++ * Visits the source of the class. -++ * -++ * @param source -++ * the name of the source file from which the class was compiled. -++ * May be null. -++ * @param debug -++ * additional debug information to compute the correspondance -++ * between source and compiled elements of the class. May be -++ * null. -++ */ -++ public void visitSource(String source, String debug) { -++ if (cv != null) { -++ cv.visitSource(source, debug); -++ } -++ } -++ -++ /** -++ * Visits the enclosing class of the class. This method must be called only -++ * if the class has an enclosing class. -++ * -++ * @param owner -++ * internal name of the enclosing class of the class. -++ * @param name -++ * the name of the method that contains the class, or -++ * null if the class is not enclosed in a method of its -++ * enclosing class. -++ * @param desc -++ * the descriptor of the method that contains the class, or -++ * null if the class is not enclosed in a method of its -++ * enclosing class. -++ */ -++ public void visitOuterClass(String owner, String name, String desc) { -++ if (cv != null) { -++ cv.visitOuterClass(owner, name, desc); -++ } -++ } -++ -++ /** -++ * Visits an annotation of the class. -++ * -++ * @param desc -++ * the class descriptor of the annotation class. -++ * @param visible -++ * true if the annotation is visible at runtime. -++ * @return a visitor to visit the annotation values, or null if -++ * this visitor is not interested in visiting this annotation. -++ */ -++ public AnnotationVisitor visitAnnotation(String desc, boolean visible) { -++ if (cv != null) { -++ return cv.visitAnnotation(desc, visible); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits an annotation on a type in the class signature. -++ * -++ * @param typeRef -++ * a reference to the annotated type. The sort of this type -++ * reference must be {@link TypeReference#CLASS_TYPE_PARAMETER -++ * CLASS_TYPE_PARAMETER}, -++ * {@link TypeReference#CLASS_TYPE_PARAMETER_BOUND -++ * CLASS_TYPE_PARAMETER_BOUND} or -++ * {@link TypeReference#CLASS_EXTENDS CLASS_EXTENDS}. See -++ * {@link TypeReference}. -++ * @param typePath -++ * the path to the annotated type argument, wildcard bound, array -++ * element type, or static inner type within 'typeRef'. May be -++ * null if the annotation targets 'typeRef' as a whole. -++ * @param desc -++ * the class descriptor of the annotation class. -++ * @param visible -++ * true if the annotation is visible at runtime. -++ * @return a visitor to visit the annotation values, or null if -++ * this visitor is not interested in visiting this annotation. -++ */ -++ public AnnotationVisitor visitTypeAnnotation(int typeRef, -++ TypePath typePath, String desc, boolean visible) { -++ if (api < Opcodes.ASM5) { -++ throw new RuntimeException(); -++ } -++ if (cv != null) { -++ return cv.visitTypeAnnotation(typeRef, typePath, desc, visible); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits a non standard attribute of the class. -++ * -++ * @param attr -++ * an attribute. -++ */ -++ public void visitAttribute(Attribute attr) { -++ if (cv != null) { -++ cv.visitAttribute(attr); -++ } -++ } -++ -++ /** -++ * Visits information about an inner class. This inner class is not -++ * necessarily a member of the class being visited. -++ * -++ * @param name -++ * the internal name of an inner class (see -++ * {@link Type#getInternalName() getInternalName}). -++ * @param outerName -++ * the internal name of the class to which the inner class -++ * belongs (see {@link Type#getInternalName() getInternalName}). -++ * May be null for not member classes. -++ * @param innerName -++ * the (simple) name of the inner class inside its enclosing -++ * class. May be null for anonymous inner classes. -++ * @param access -++ * the access flags of the inner class as originally declared in -++ * the enclosing class. -++ */ -++ public void visitInnerClass(String name, String outerName, -++ String innerName, int access) { -++ if (cv != null) { -++ cv.visitInnerClass(name, outerName, innerName, access); -++ } -++ } -++ -++ /** -++ * Visits a field of the class. -++ * -++ * @param access -++ * the field's access flags (see {@link Opcodes}). This parameter -++ * also indicates if the field is synthetic and/or deprecated. -++ * @param name -++ * the field's name. -++ * @param desc -++ * the field's descriptor (see {@link Type Type}). -++ * @param signature -++ * the field's signature. May be null if the field's -++ * type does not use generic types. -++ * @param value -++ * the field's initial value. This parameter, which may be -++ * null if the field does not have an initial value, -++ * must be an {@link Integer}, a {@link Float}, a {@link Long}, a -++ * {@link Double} or a {@link String} (for int, -++ * float, long or String fields -++ * respectively). This parameter is only used for static -++ * fields. Its value is ignored for non static fields, which -++ * must be initialized through bytecode instructions in -++ * constructors or methods. -++ * @return a visitor to visit field annotations and attributes, or -++ * null if this class visitor is not interested in visiting -++ * these annotations and attributes. -++ */ -++ public FieldVisitor visitField(int access, String name, String desc, -++ String signature, Object value) { -++ if (cv != null) { -++ return cv.visitField(access, name, desc, signature, value); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits a method of the class. This method must return a new -++ * {@link MethodVisitor} instance (or null) each time it is called, -++ * i.e., it should not return a previously returned visitor. -++ * -++ * @param access -++ * the method's access flags (see {@link Opcodes}). This -++ * parameter also indicates if the method is synthetic and/or -++ * deprecated. -++ * @param name -++ * the method's name. -++ * @param desc -++ * the method's descriptor (see {@link Type Type}). -++ * @param signature -++ * the method's signature. May be null if the method -++ * parameters, return type and exceptions do not use generic -++ * types. -++ * @param exceptions -++ * the internal names of the method's exception classes (see -++ * {@link Type#getInternalName() getInternalName}). May be -++ * null. -++ * @return an object to visit the byte code of the method, or null -++ * if this class visitor is not interested in visiting the code of -++ * this method. -++ */ -++ public MethodVisitor visitMethod(int access, String name, String desc, -++ String signature, String[] exceptions) { -++ if (cv != null) { -++ return cv.visitMethod(access, name, desc, signature, exceptions); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits the end of the class. This method, which is the last one to be -++ * called, is used to inform the visitor that all the fields and methods of -++ * the class have been visited. -++ */ -++ public void visitEnd() { -++ if (cv != null) { -++ cv.visitEnd(); -++ } -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/ClassWriter.java b/contrib/asm/src/org/objectweb/asm/ClassWriter.java -+new file mode 100644 -+index 0000000..63e1d7e -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/ClassWriter.java -+@@ -0,0 +1,1776 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * A {@link ClassVisitor} that generates classes in bytecode form. More -++ * precisely this visitor generates a byte array conforming to the Java class -++ * file format. It can be used alone, to generate a Java class "from scratch", -++ * or with one or more {@link ClassReader ClassReader} and adapter class visitor -++ * to generate a modified class from one or more existing Java classes. -++ * -++ * @author Eric Bruneton -++ */ -++public class ClassWriter extends ClassVisitor { -++ -++ /** -++ * Flag to automatically compute the maximum stack size and the maximum -++ * number of local variables of methods. If this flag is set, then the -++ * arguments of the {@link MethodVisitor#visitMaxs visitMaxs} method of the -++ * {@link MethodVisitor} returned by the {@link #visitMethod visitMethod} -++ * method will be ignored, and computed automatically from the signature and -++ * the bytecode of each method. -++ * -++ * @see #ClassWriter(int) -++ */ -++ public static final int COMPUTE_MAXS = 1; -++ -++ /** -++ * Flag to automatically compute the stack map frames of methods from -++ * scratch. If this flag is set, then the calls to the -++ * {@link MethodVisitor#visitFrame} method are ignored, and the stack map -++ * frames are recomputed from the methods bytecode. The arguments of the -++ * {@link MethodVisitor#visitMaxs visitMaxs} method are also ignored and -++ * recomputed from the bytecode. In other words, computeFrames implies -++ * computeMaxs. -++ * -++ * @see #ClassWriter(int) -++ */ -++ public static final int COMPUTE_FRAMES = 2; -++ -++ /** -++ * Pseudo access flag to distinguish between the synthetic attribute and the -++ * synthetic access flag. -++ */ -++ static final int ACC_SYNTHETIC_ATTRIBUTE = 0x40000; -++ -++ /** -++ * Factor to convert from ACC_SYNTHETIC_ATTRIBUTE to Opcode.ACC_SYNTHETIC. -++ */ -++ static final int TO_ACC_SYNTHETIC = ACC_SYNTHETIC_ATTRIBUTE -++ / Opcodes.ACC_SYNTHETIC; -++ -++ /** -++ * The type of instructions without any argument. -++ */ -++ static final int NOARG_INSN = 0; -++ -++ /** -++ * The type of instructions with an signed byte argument. -++ */ -++ static final int SBYTE_INSN = 1; -++ -++ /** -++ * The type of instructions with an signed short argument. -++ */ -++ static final int SHORT_INSN = 2; -++ -++ /** -++ * The type of instructions with a local variable index argument. -++ */ -++ static final int VAR_INSN = 3; -++ -++ /** -++ * The type of instructions with an implicit local variable index argument. -++ */ -++ static final int IMPLVAR_INSN = 4; -++ -++ /** -++ * The type of instructions with a type descriptor argument. -++ */ -++ static final int TYPE_INSN = 5; -++ -++ /** -++ * The type of field and method invocations instructions. -++ */ -++ static final int FIELDORMETH_INSN = 6; -++ -++ /** -++ * The type of the INVOKEINTERFACE/INVOKEDYNAMIC instruction. -++ */ -++ static final int ITFMETH_INSN = 7; -++ -++ /** -++ * The type of the INVOKEDYNAMIC instruction. -++ */ -++ static final int INDYMETH_INSN = 8; -++ -++ /** -++ * The type of instructions with a 2 bytes bytecode offset label. -++ */ -++ static final int LABEL_INSN = 9; -++ -++ /** -++ * The type of instructions with a 4 bytes bytecode offset label. -++ */ -++ static final int LABELW_INSN = 10; -++ -++ /** -++ * The type of the LDC instruction. -++ */ -++ static final int LDC_INSN = 11; -++ -++ /** -++ * The type of the LDC_W and LDC2_W instructions. -++ */ -++ static final int LDCW_INSN = 12; -++ -++ /** -++ * The type of the IINC instruction. -++ */ -++ static final int IINC_INSN = 13; -++ -++ /** -++ * The type of the TABLESWITCH instruction. -++ */ -++ static final int TABL_INSN = 14; -++ -++ /** -++ * The type of the LOOKUPSWITCH instruction. -++ */ -++ static final int LOOK_INSN = 15; -++ -++ /** -++ * The type of the MULTIANEWARRAY instruction. -++ */ -++ static final int MANA_INSN = 16; -++ -++ /** -++ * The type of the WIDE instruction. -++ */ -++ static final int WIDE_INSN = 17; -++ -++ /** -++ * The instruction types of all JVM opcodes. -++ */ -++ static final byte[] TYPE; -++ -++ /** -++ * The type of CONSTANT_Class constant pool items. -++ */ -++ static final int CLASS = 7; -++ -++ /** -++ * The type of CONSTANT_Fieldref constant pool items. -++ */ -++ static final int FIELD = 9; -++ -++ /** -++ * The type of CONSTANT_Methodref constant pool items. -++ */ -++ static final int METH = 10; -++ -++ /** -++ * The type of CONSTANT_InterfaceMethodref constant pool items. -++ */ -++ static final int IMETH = 11; -++ -++ /** -++ * The type of CONSTANT_String constant pool items. -++ */ -++ static final int STR = 8; -++ -++ /** -++ * The type of CONSTANT_Integer constant pool items. -++ */ -++ static final int INT = 3; -++ -++ /** -++ * The type of CONSTANT_Float constant pool items. -++ */ -++ static final int FLOAT = 4; -++ -++ /** -++ * The type of CONSTANT_Long constant pool items. -++ */ -++ static final int LONG = 5; -++ -++ /** -++ * The type of CONSTANT_Double constant pool items. -++ */ -++ static final int DOUBLE = 6; -++ -++ /** -++ * The type of CONSTANT_NameAndType constant pool items. -++ */ -++ static final int NAME_TYPE = 12; -++ -++ /** -++ * The type of CONSTANT_Utf8 constant pool items. -++ */ -++ static final int UTF8 = 1; -++ -++ /** -++ * The type of CONSTANT_MethodType constant pool items. -++ */ -++ static final int MTYPE = 16; -++ -++ /** -++ * The type of CONSTANT_MethodHandle constant pool items. -++ */ -++ static final int HANDLE = 15; -++ -++ /** -++ * The type of CONSTANT_InvokeDynamic constant pool items. -++ */ -++ static final int INDY = 18; -++ -++ /** -++ * The base value for all CONSTANT_MethodHandle constant pool items. -++ * Internally, ASM store the 9 variations of CONSTANT_MethodHandle into 9 -++ * different items. -++ */ -++ static final int HANDLE_BASE = 20; -++ -++ /** -++ * Normal type Item stored in the ClassWriter {@link ClassWriter#typeTable}, -++ * instead of the constant pool, in order to avoid clashes with normal -++ * constant pool items in the ClassWriter constant pool's hash table. -++ */ -++ static final int TYPE_NORMAL = 30; -++ -++ /** -++ * Uninitialized type Item stored in the ClassWriter -++ * {@link ClassWriter#typeTable}, instead of the constant pool, in order to -++ * avoid clashes with normal constant pool items in the ClassWriter constant -++ * pool's hash table. -++ */ -++ static final int TYPE_UNINIT = 31; -++ -++ /** -++ * Merged type Item stored in the ClassWriter {@link ClassWriter#typeTable}, -++ * instead of the constant pool, in order to avoid clashes with normal -++ * constant pool items in the ClassWriter constant pool's hash table. -++ */ -++ static final int TYPE_MERGED = 32; -++ -++ /** -++ * The type of BootstrapMethods items. These items are stored in a special -++ * class attribute named BootstrapMethods and not in the constant pool. -++ */ -++ static final int BSM = 33; -++ -++ /** -++ * The class reader from which this class writer was constructed, if any. -++ */ -++ ClassReader cr; -++ -++ /** -++ * Minor and major version numbers of the class to be generated. -++ */ -++ int version; -++ -++ /** -++ * Index of the next item to be added in the constant pool. -++ */ -++ int index; -++ -++ /** -++ * The constant pool of this class. -++ */ -++ final ByteVector pool; -++ -++ /** -++ * The constant pool's hash table data. -++ */ -++ Item[] items; -++ -++ /** -++ * The threshold of the constant pool's hash table. -++ */ -++ int threshold; -++ -++ /** -++ * A reusable key used to look for items in the {@link #items} hash table. -++ */ -++ final Item key; -++ -++ /** -++ * A reusable key used to look for items in the {@link #items} hash table. -++ */ -++ final Item key2; -++ -++ /** -++ * A reusable key used to look for items in the {@link #items} hash table. -++ */ -++ final Item key3; -++ -++ /** -++ * A reusable key used to look for items in the {@link #items} hash table. -++ */ -++ final Item key4; -++ -++ /** -++ * A type table used to temporarily store internal names that will not -++ * necessarily be stored in the constant pool. This type table is used by -++ * the control flow and data flow analysis algorithm used to compute stack -++ * map frames from scratch. This array associates to each index i -++ * the Item whose index is i. All Item objects stored in this array -++ * are also stored in the {@link #items} hash table. These two arrays allow -++ * to retrieve an Item from its index or, conversely, to get the index of an -++ * Item from its value. Each Item stores an internal name in its -++ * {@link Item#strVal1} field. -++ */ -++ Item[] typeTable; -++ -++ /** -++ * Number of elements in the {@link #typeTable} array. -++ */ -++ private short typeCount; -++ -++ /** -++ * The access flags of this class. -++ */ -++ private int access; -++ -++ /** -++ * The constant pool item that contains the internal name of this class. -++ */ -++ private int name; -++ -++ /** -++ * The internal name of this class. -++ */ -++ String thisName; -++ -++ /** -++ * The constant pool item that contains the signature of this class. -++ */ -++ private int signature; -++ -++ /** -++ * The constant pool item that contains the internal name of the super class -++ * of this class. -++ */ -++ private int superName; -++ -++ /** -++ * Number of interfaces implemented or extended by this class or interface. -++ */ -++ private int interfaceCount; -++ -++ /** -++ * The interfaces implemented or extended by this class or interface. More -++ * precisely, this array contains the indexes of the constant pool items -++ * that contain the internal names of these interfaces. -++ */ -++ private int[] interfaces; -++ -++ /** -++ * The index of the constant pool item that contains the name of the source -++ * file from which this class was compiled. -++ */ -++ private int sourceFile; -++ -++ /** -++ * The SourceDebug attribute of this class. -++ */ -++ private ByteVector sourceDebug; -++ -++ /** -++ * The constant pool item that contains the name of the enclosing class of -++ * this class. -++ */ -++ private int enclosingMethodOwner; -++ -++ /** -++ * The constant pool item that contains the name and descriptor of the -++ * enclosing method of this class. -++ */ -++ private int enclosingMethod; -++ -++ /** -++ * The runtime visible annotations of this class. -++ */ -++ private AnnotationWriter anns; -++ -++ /** -++ * The runtime invisible annotations of this class. -++ */ -++ private AnnotationWriter ianns; -++ -++ /** -++ * The runtime visible type annotations of this class. -++ */ -++ private AnnotationWriter tanns; -++ -++ /** -++ * The runtime invisible type annotations of this class. -++ */ -++ private AnnotationWriter itanns; -++ -++ /** -++ * The non standard attributes of this class. -++ */ -++ private Attribute attrs; -++ -++ /** -++ * The number of entries in the InnerClasses attribute. -++ */ -++ private int innerClassesCount; -++ -++ /** -++ * The InnerClasses attribute. -++ */ -++ private ByteVector innerClasses; -++ -++ /** -++ * The number of entries in the BootstrapMethods attribute. -++ */ -++ int bootstrapMethodsCount; -++ -++ /** -++ * The BootstrapMethods attribute. -++ */ -++ ByteVector bootstrapMethods; -++ -++ /** -++ * The fields of this class. These fields are stored in a linked list of -++ * {@link FieldWriter} objects, linked to each other by their -++ * {@link FieldWriter#fv} field. This field stores the first element of this -++ * list. -++ */ -++ FieldWriter firstField; -++ -++ /** -++ * The fields of this class. These fields are stored in a linked list of -++ * {@link FieldWriter} objects, linked to each other by their -++ * {@link FieldWriter#fv} field. This field stores the last element of this -++ * list. -++ */ -++ FieldWriter lastField; -++ -++ /** -++ * The methods of this class. These methods are stored in a linked list of -++ * {@link MethodWriter} objects, linked to each other by their -++ * {@link MethodWriter#mv} field. This field stores the first element of -++ * this list. -++ */ -++ MethodWriter firstMethod; -++ -++ /** -++ * The methods of this class. These methods are stored in a linked list of -++ * {@link MethodWriter} objects, linked to each other by their -++ * {@link MethodWriter#mv} field. This field stores the last element of this -++ * list. -++ */ -++ MethodWriter lastMethod; -++ -++ /** -++ * true if the maximum stack size and number of local variables -++ * must be automatically computed. -++ */ -++ private boolean computeMaxs; -++ -++ /** -++ * true if the stack map frames must be recomputed from scratch. -++ */ -++ private boolean computeFrames; -++ -++ /** -++ * true if the stack map tables of this class are invalid. The -++ * {@link MethodWriter#resizeInstructions} method cannot transform existing -++ * stack map tables, and so produces potentially invalid classes when it is -++ * executed. In this case the class is reread and rewritten with the -++ * {@link #COMPUTE_FRAMES} option (the resizeInstructions method can resize -++ * stack map tables when this option is used). -++ */ -++ boolean invalidFrames; -++ -++ // ------------------------------------------------------------------------ -++ // Static initializer -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Computes the instruction types of JVM opcodes. -++ */ -++ static { -++ int i; -++ byte[] b = new byte[220]; -++ String s = "AAAAAAAAAAAAAAAABCLMMDDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAADD" -++ + "DDDEEEEEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" -++ + "AAAAAAAAAAAAAAAAANAAAAAAAAAAAAAAAAAAAAJJJJJJJJJJJJJJJJDOPAA" -++ + "AAAAGGGGGGGHIFBFAAFFAARQJJKKJJJJJJJJJJJJJJJJJJ"; -++ for (i = 0; i < b.length; ++i) { -++ b[i] = (byte) (s.charAt(i) - 'A'); -++ } -++ TYPE = b; -++ -++ // code to generate the above string -++ // -++ // // SBYTE_INSN instructions -++ // b[Constants.NEWARRAY] = SBYTE_INSN; -++ // b[Constants.BIPUSH] = SBYTE_INSN; -++ // -++ // // SHORT_INSN instructions -++ // b[Constants.SIPUSH] = SHORT_INSN; -++ // -++ // // (IMPL)VAR_INSN instructions -++ // b[Constants.RET] = VAR_INSN; -++ // for (i = Constants.ILOAD; i <= Constants.ALOAD; ++i) { -++ // b[i] = VAR_INSN; -++ // } -++ // for (i = Constants.ISTORE; i <= Constants.ASTORE; ++i) { -++ // b[i] = VAR_INSN; -++ // } -++ // for (i = 26; i <= 45; ++i) { // ILOAD_0 to ALOAD_3 -++ // b[i] = IMPLVAR_INSN; -++ // } -++ // for (i = 59; i <= 78; ++i) { // ISTORE_0 to ASTORE_3 -++ // b[i] = IMPLVAR_INSN; -++ // } -++ // -++ // // TYPE_INSN instructions -++ // b[Constants.NEW] = TYPE_INSN; -++ // b[Constants.ANEWARRAY] = TYPE_INSN; -++ // b[Constants.CHECKCAST] = TYPE_INSN; -++ // b[Constants.INSTANCEOF] = TYPE_INSN; -++ // -++ // // (Set)FIELDORMETH_INSN instructions -++ // for (i = Constants.GETSTATIC; i <= Constants.INVOKESTATIC; ++i) { -++ // b[i] = FIELDORMETH_INSN; -++ // } -++ // b[Constants.INVOKEINTERFACE] = ITFMETH_INSN; -++ // b[Constants.INVOKEDYNAMIC] = INDYMETH_INSN; -++ // -++ // // LABEL(W)_INSN instructions -++ // for (i = Constants.IFEQ; i <= Constants.JSR; ++i) { -++ // b[i] = LABEL_INSN; -++ // } -++ // b[Constants.IFNULL] = LABEL_INSN; -++ // b[Constants.IFNONNULL] = LABEL_INSN; -++ // b[200] = LABELW_INSN; // GOTO_W -++ // b[201] = LABELW_INSN; // JSR_W -++ // // temporary opcodes used internally by ASM - see Label and -++ // MethodWriter -++ // for (i = 202; i < 220; ++i) { -++ // b[i] = LABEL_INSN; -++ // } -++ // -++ // // LDC(_W) instructions -++ // b[Constants.LDC] = LDC_INSN; -++ // b[19] = LDCW_INSN; // LDC_W -++ // b[20] = LDCW_INSN; // LDC2_W -++ // -++ // // special instructions -++ // b[Constants.IINC] = IINC_INSN; -++ // b[Constants.TABLESWITCH] = TABL_INSN; -++ // b[Constants.LOOKUPSWITCH] = LOOK_INSN; -++ // b[Constants.MULTIANEWARRAY] = MANA_INSN; -++ // b[196] = WIDE_INSN; // WIDE -++ // -++ // for (i = 0; i < b.length; ++i) { -++ // System.err.print((char)('A' + b[i])); -++ // } -++ // System.err.println(); -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Constructor -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Constructs a new {@link ClassWriter} object. -++ * -++ * @param flags -++ * option flags that can be used to modify the default behavior -++ * of this class. See {@link #COMPUTE_MAXS}, -++ * {@link #COMPUTE_FRAMES}. -++ */ -++ public ClassWriter(final int flags) { -++ super(Opcodes.ASM5); -++ index = 1; -++ pool = new ByteVector(); -++ items = new Item[256]; -++ threshold = (int) (0.75d * items.length); -++ key = new Item(); -++ key2 = new Item(); -++ key3 = new Item(); -++ key4 = new Item(); -++ this.computeMaxs = (flags & COMPUTE_MAXS) != 0; -++ this.computeFrames = (flags & COMPUTE_FRAMES) != 0; -++ } -++ -++ /** -++ * Constructs a new {@link ClassWriter} object and enables optimizations for -++ * "mostly add" bytecode transformations. These optimizations are the -++ * following: -++ * -++ *
    -++ *
  • The constant pool from the original class is copied as is in the new -++ * class, which saves time. New constant pool entries will be added at the -++ * end if necessary, but unused constant pool entries won't be -++ * removed.
  • -++ *
  • Methods that are not transformed are copied as is in the new class, -++ * directly from the original class bytecode (i.e. without emitting visit -++ * events for all the method instructions), which saves a lot of -++ * time. Untransformed methods are detected by the fact that the -++ * {@link ClassReader} receives {@link MethodVisitor} objects that come from -++ * a {@link ClassWriter} (and not from any other {@link ClassVisitor} -++ * instance).
  • -++ *
-++ * -++ * @param classReader -++ * the {@link ClassReader} used to read the original class. It -++ * will be used to copy the entire constant pool from the -++ * original class and also to copy other fragments of original -++ * bytecode where applicable. -++ * @param flags -++ * option flags that can be used to modify the default behavior -++ * of this class. These option flags do not affect methods -++ * that are copied as is in the new class. This means that the -++ * maximum stack size nor the stack frames will be computed for -++ * these methods. See {@link #COMPUTE_MAXS}, -++ * {@link #COMPUTE_FRAMES}. -++ */ -++ public ClassWriter(final ClassReader classReader, final int flags) { -++ this(flags); -++ classReader.copyPool(this); -++ this.cr = classReader; -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Implementation of the ClassVisitor abstract class -++ // ------------------------------------------------------------------------ -++ -++ @Override -++ public final void visit(final int version, final int access, -++ final String name, final String signature, final String superName, -++ final String[] interfaces) { -++ this.version = version; -++ this.access = access; -++ this.name = newClass(name); -++ thisName = name; -++ if (ClassReader.SIGNATURES && signature != null) { -++ this.signature = newUTF8(signature); -++ } -++ this.superName = superName == null ? 0 : newClass(superName); -++ if (interfaces != null && interfaces.length > 0) { -++ interfaceCount = interfaces.length; -++ this.interfaces = new int[interfaceCount]; -++ for (int i = 0; i < interfaceCount; ++i) { -++ this.interfaces[i] = newClass(interfaces[i]); -++ } -++ } -++ } -++ -++ @Override -++ public final void visitSource(final String file, final String debug) { -++ if (file != null) { -++ sourceFile = newUTF8(file); -++ } -++ if (debug != null) { -++ sourceDebug = new ByteVector().encodeUTF8(debug, 0, -++ Integer.MAX_VALUE); -++ } -++ } -++ -++ @Override -++ public final void visitOuterClass(final String owner, final String name, -++ final String desc) { -++ enclosingMethodOwner = newClass(owner); -++ if (name != null && desc != null) { -++ enclosingMethod = newNameType(name, desc); -++ } -++ } -++ -++ @Override -++ public final AnnotationVisitor visitAnnotation(final String desc, -++ final boolean visible) { -++ if (!ClassReader.ANNOTATIONS) { -++ return null; -++ } -++ ByteVector bv = new ByteVector(); -++ // write type, and reserve space for values count -++ bv.putShort(newUTF8(desc)).putShort(0); -++ AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv, 2); -++ if (visible) { -++ aw.next = anns; -++ anns = aw; -++ } else { -++ aw.next = ianns; -++ ianns = aw; -++ } -++ return aw; -++ } -++ -++ @Override -++ public final AnnotationVisitor visitTypeAnnotation(int typeRef, -++ TypePath typePath, final String desc, final boolean visible) { -++ if (!ClassReader.ANNOTATIONS) { -++ return null; -++ } -++ ByteVector bv = new ByteVector(); -++ // write target_type and target_info -++ AnnotationWriter.putTarget(typeRef, typePath, bv); -++ // write type, and reserve space for values count -++ bv.putShort(newUTF8(desc)).putShort(0); -++ AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv, -++ bv.length - 2); -++ if (visible) { -++ aw.next = tanns; -++ tanns = aw; -++ } else { -++ aw.next = itanns; -++ itanns = aw; -++ } -++ return aw; -++ } -++ -++ @Override -++ public final void visitAttribute(final Attribute attr) { -++ attr.next = attrs; -++ attrs = attr; -++ } -++ -++ @Override -++ public final void visitInnerClass(final String name, -++ final String outerName, final String innerName, final int access) { -++ if (innerClasses == null) { -++ innerClasses = new ByteVector(); -++ } -++ // Sec. 4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the -++ // constant_pool table which represents a class or interface C that is -++ // not a package member must have exactly one corresponding entry in the -++ // classes array". To avoid duplicates we keep track in the intVal field -++ // of the Item of each CONSTANT_Class_info entry C whether an inner -++ // class entry has already been added for C (this field is unused for -++ // class entries, and changing its value does not change the hashcode -++ // and equality tests). If so we store the index of this inner class -++ // entry (plus one) in intVal. This hack allows duplicate detection in -++ // O(1) time. -++ Item nameItem = newClassItem(name); -++ if (nameItem.intVal == 0) { -++ ++innerClassesCount; -++ innerClasses.putShort(nameItem.index); -++ innerClasses.putShort(outerName == null ? 0 : newClass(outerName)); -++ innerClasses.putShort(innerName == null ? 0 : newUTF8(innerName)); -++ innerClasses.putShort(access); -++ nameItem.intVal = innerClassesCount; -++ } else { -++ // Compare the inner classes entry nameItem.intVal - 1 with the -++ // arguments of this method and throw an exception if there is a -++ // difference? -++ } -++ } -++ -++ @Override -++ public final FieldVisitor visitField(final int access, final String name, -++ final String desc, final String signature, final Object value) { -++ return new FieldWriter(this, access, name, desc, signature, value); -++ } -++ -++ @Override -++ public final MethodVisitor visitMethod(final int access, final String name, -++ final String desc, final String signature, final String[] exceptions) { -++ return new MethodWriter(this, access, name, desc, signature, -++ exceptions, computeMaxs, computeFrames); -++ } -++ -++ @Override -++ public final void visitEnd() { -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Other public methods -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Returns the bytecode of the class that was build with this class writer. -++ * -++ * @return the bytecode of the class that was build with this class writer. -++ */ -++ public byte[] toByteArray() { -++ if (index > 0xFFFF) { -++ throw new RuntimeException("Class file too large!"); -++ } -++ // computes the real size of the bytecode of this class -++ int size = 24 + 2 * interfaceCount; -++ int nbFields = 0; -++ FieldWriter fb = firstField; -++ while (fb != null) { -++ ++nbFields; -++ size += fb.getSize(); -++ fb = (FieldWriter) fb.fv; -++ } -++ int nbMethods = 0; -++ MethodWriter mb = firstMethod; -++ while (mb != null) { -++ ++nbMethods; -++ size += mb.getSize(); -++ mb = (MethodWriter) mb.mv; -++ } -++ int attributeCount = 0; -++ if (bootstrapMethods != null) { -++ // we put it as first attribute in order to improve a bit -++ // ClassReader.copyBootstrapMethods -++ ++attributeCount; -++ size += 8 + bootstrapMethods.length; -++ newUTF8("BootstrapMethods"); -++ } -++ if (ClassReader.SIGNATURES && signature != 0) { -++ ++attributeCount; -++ size += 8; -++ newUTF8("Signature"); -++ } -++ if (sourceFile != 0) { -++ ++attributeCount; -++ size += 8; -++ newUTF8("SourceFile"); -++ } -++ if (sourceDebug != null) { -++ ++attributeCount; -++ size += sourceDebug.length + 6; -++ newUTF8("SourceDebugExtension"); -++ } -++ if (enclosingMethodOwner != 0) { -++ ++attributeCount; -++ size += 10; -++ newUTF8("EnclosingMethod"); -++ } -++ if ((access & Opcodes.ACC_DEPRECATED) != 0) { -++ ++attributeCount; -++ size += 6; -++ newUTF8("Deprecated"); -++ } -++ if ((access & Opcodes.ACC_SYNTHETIC) != 0) { -++ if ((version & 0xFFFF) < Opcodes.V1_5 -++ || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) { -++ ++attributeCount; -++ size += 6; -++ newUTF8("Synthetic"); -++ } -++ } -++ if (innerClasses != null) { -++ ++attributeCount; -++ size += 8 + innerClasses.length; -++ newUTF8("InnerClasses"); -++ } -++ if (ClassReader.ANNOTATIONS && anns != null) { -++ ++attributeCount; -++ size += 8 + anns.getSize(); -++ newUTF8("RuntimeVisibleAnnotations"); -++ } -++ if (ClassReader.ANNOTATIONS && ianns != null) { -++ ++attributeCount; -++ size += 8 + ianns.getSize(); -++ newUTF8("RuntimeInvisibleAnnotations"); -++ } -++ if (ClassReader.ANNOTATIONS && tanns != null) { -++ ++attributeCount; -++ size += 8 + tanns.getSize(); -++ newUTF8("RuntimeVisibleTypeAnnotations"); -++ } -++ if (ClassReader.ANNOTATIONS && itanns != null) { -++ ++attributeCount; -++ size += 8 + itanns.getSize(); -++ newUTF8("RuntimeInvisibleTypeAnnotations"); -++ } -++ if (attrs != null) { -++ attributeCount += attrs.getCount(); -++ size += attrs.getSize(this, null, 0, -1, -1); -++ } -++ size += pool.length; -++ // allocates a byte vector of this size, in order to avoid unnecessary -++ // arraycopy operations in the ByteVector.enlarge() method -++ ByteVector out = new ByteVector(size); -++ out.putInt(0xCAFEBABE).putInt(version); -++ out.putShort(index).putByteArray(pool.data, 0, pool.length); -++ int mask = Opcodes.ACC_DEPRECATED | ACC_SYNTHETIC_ATTRIBUTE -++ | ((access & ACC_SYNTHETIC_ATTRIBUTE) / TO_ACC_SYNTHETIC); -++ out.putShort(access & ~mask).putShort(name).putShort(superName); -++ out.putShort(interfaceCount); -++ for (int i = 0; i < interfaceCount; ++i) { -++ out.putShort(interfaces[i]); -++ } -++ out.putShort(nbFields); -++ fb = firstField; -++ while (fb != null) { -++ fb.put(out); -++ fb = (FieldWriter) fb.fv; -++ } -++ out.putShort(nbMethods); -++ mb = firstMethod; -++ while (mb != null) { -++ mb.put(out); -++ mb = (MethodWriter) mb.mv; -++ } -++ out.putShort(attributeCount); -++ if (bootstrapMethods != null) { -++ out.putShort(newUTF8("BootstrapMethods")); -++ out.putInt(bootstrapMethods.length + 2).putShort( -++ bootstrapMethodsCount); -++ out.putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length); -++ } -++ if (ClassReader.SIGNATURES && signature != 0) { -++ out.putShort(newUTF8("Signature")).putInt(2).putShort(signature); -++ } -++ if (sourceFile != 0) { -++ out.putShort(newUTF8("SourceFile")).putInt(2).putShort(sourceFile); -++ } -++ if (sourceDebug != null) { -++ int len = sourceDebug.length; -++ out.putShort(newUTF8("SourceDebugExtension")).putInt(len); -++ out.putByteArray(sourceDebug.data, 0, len); -++ } -++ if (enclosingMethodOwner != 0) { -++ out.putShort(newUTF8("EnclosingMethod")).putInt(4); -++ out.putShort(enclosingMethodOwner).putShort(enclosingMethod); -++ } -++ if ((access & Opcodes.ACC_DEPRECATED) != 0) { -++ out.putShort(newUTF8("Deprecated")).putInt(0); -++ } -++ if ((access & Opcodes.ACC_SYNTHETIC) != 0) { -++ if ((version & 0xFFFF) < Opcodes.V1_5 -++ || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) { -++ out.putShort(newUTF8("Synthetic")).putInt(0); -++ } -++ } -++ if (innerClasses != null) { -++ out.putShort(newUTF8("InnerClasses")); -++ out.putInt(innerClasses.length + 2).putShort(innerClassesCount); -++ out.putByteArray(innerClasses.data, 0, innerClasses.length); -++ } -++ if (ClassReader.ANNOTATIONS && anns != null) { -++ out.putShort(newUTF8("RuntimeVisibleAnnotations")); -++ anns.put(out); -++ } -++ if (ClassReader.ANNOTATIONS && ianns != null) { -++ out.putShort(newUTF8("RuntimeInvisibleAnnotations")); -++ ianns.put(out); -++ } -++ if (ClassReader.ANNOTATIONS && tanns != null) { -++ out.putShort(newUTF8("RuntimeVisibleTypeAnnotations")); -++ tanns.put(out); -++ } -++ if (ClassReader.ANNOTATIONS && itanns != null) { -++ out.putShort(newUTF8("RuntimeInvisibleTypeAnnotations")); -++ itanns.put(out); -++ } -++ if (attrs != null) { -++ attrs.put(this, null, 0, -1, -1, out); -++ } -++ if (invalidFrames) { -++ anns = null; -++ ianns = null; -++ attrs = null; -++ innerClassesCount = 0; -++ innerClasses = null; -++ bootstrapMethodsCount = 0; -++ bootstrapMethods = null; -++ firstField = null; -++ lastField = null; -++ firstMethod = null; -++ lastMethod = null; -++ computeMaxs = false; -++ computeFrames = true; -++ invalidFrames = false; -++ new ClassReader(out.data).accept(this, ClassReader.SKIP_FRAMES); -++ return toByteArray(); -++ } -++ return out.data; -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Utility methods: constant pool management -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Adds a number or string constant to the constant pool of the class being -++ * build. Does nothing if the constant pool already contains a similar item. -++ * -++ * @param cst -++ * the value of the constant to be added to the constant pool. -++ * This parameter must be an {@link Integer}, a {@link Float}, a -++ * {@link Long}, a {@link Double}, a {@link String} or a -++ * {@link Type}. -++ * @return a new or already existing constant item with the given value. -++ */ -++ Item newConstItem(final Object cst) { -++ if (cst instanceof Integer) { -++ int val = ((Integer) cst).intValue(); -++ return newInteger(val); -++ } else if (cst instanceof Byte) { -++ int val = ((Byte) cst).intValue(); -++ return newInteger(val); -++ } else if (cst instanceof Character) { -++ int val = ((Character) cst).charValue(); -++ return newInteger(val); -++ } else if (cst instanceof Short) { -++ int val = ((Short) cst).intValue(); -++ return newInteger(val); -++ } else if (cst instanceof Boolean) { -++ int val = ((Boolean) cst).booleanValue() ? 1 : 0; -++ return newInteger(val); -++ } else if (cst instanceof Float) { -++ float val = ((Float) cst).floatValue(); -++ return newFloat(val); -++ } else if (cst instanceof Long) { -++ long val = ((Long) cst).longValue(); -++ return newLong(val); -++ } else if (cst instanceof Double) { -++ double val = ((Double) cst).doubleValue(); -++ return newDouble(val); -++ } else if (cst instanceof String) { -++ return newString((String) cst); -++ } else if (cst instanceof Type) { -++ Type t = (Type) cst; -++ int s = t.getSort(); -++ if (s == Type.OBJECT) { -++ return newClassItem(t.getInternalName()); -++ } else if (s == Type.METHOD) { -++ return newMethodTypeItem(t.getDescriptor()); -++ } else { // s == primitive type or array -++ return newClassItem(t.getDescriptor()); -++ } -++ } else if (cst instanceof Handle) { -++ Handle h = (Handle) cst; -++ return newHandleItem(h.tag, h.owner, h.name, h.desc); -++ } else { -++ throw new IllegalArgumentException("value " + cst); -++ } -++ } -++ -++ /** -++ * Adds a number or string constant to the constant pool of the class being -++ * build. Does nothing if the constant pool already contains a similar item. -++ * This method is intended for {@link Attribute} sub classes, and is -++ * normally not needed by class generators or adapters. -++ * -++ * @param cst -++ * the value of the constant to be added to the constant pool. -++ * This parameter must be an {@link Integer}, a {@link Float}, a -++ * {@link Long}, a {@link Double} or a {@link String}. -++ * @return the index of a new or already existing constant item with the -++ * given value. -++ */ -++ public int newConst(final Object cst) { -++ return newConstItem(cst).index; -++ } -++ -++ /** -++ * Adds an UTF8 string to the constant pool of the class being build. Does -++ * nothing if the constant pool already contains a similar item. This -++ * method is intended for {@link Attribute} sub classes, and is normally not -++ * needed by class generators or adapters. -++ * -++ * @param value -++ * the String value. -++ * @return the index of a new or already existing UTF8 item. -++ */ -++ public int newUTF8(final String value) { -++ key.set(UTF8, value, null, null); -++ Item result = get(key); -++ if (result == null) { -++ pool.putByte(UTF8).putUTF8(value); -++ result = new Item(index++, key); -++ put(result); -++ } -++ return result.index; -++ } -++ -++ /** -++ * Adds a class reference to the constant pool of the class being build. -++ * Does nothing if the constant pool already contains a similar item. -++ * This method is intended for {@link Attribute} sub classes, and is -++ * normally not needed by class generators or adapters. -++ * -++ * @param value -++ * the internal name of the class. -++ * @return a new or already existing class reference item. -++ */ -++ Item newClassItem(final String value) { -++ key2.set(CLASS, value, null, null); -++ Item result = get(key2); -++ if (result == null) { -++ pool.put12(CLASS, newUTF8(value)); -++ result = new Item(index++, key2); -++ put(result); -++ } -++ return result; -++ } -++ -++ /** -++ * Adds a class reference to the constant pool of the class being build. -++ * Does nothing if the constant pool already contains a similar item. -++ * This method is intended for {@link Attribute} sub classes, and is -++ * normally not needed by class generators or adapters. -++ * -++ * @param value -++ * the internal name of the class. -++ * @return the index of a new or already existing class reference item. -++ */ -++ public int newClass(final String value) { -++ return newClassItem(value).index; -++ } -++ -++ /** -++ * Adds a method type reference to the constant pool of the class being -++ * build. Does nothing if the constant pool already contains a similar item. -++ * This method is intended for {@link Attribute} sub classes, and is -++ * normally not needed by class generators or adapters. -++ * -++ * @param methodDesc -++ * method descriptor of the method type. -++ * @return a new or already existing method type reference item. -++ */ -++ Item newMethodTypeItem(final String methodDesc) { -++ key2.set(MTYPE, methodDesc, null, null); -++ Item result = get(key2); -++ if (result == null) { -++ pool.put12(MTYPE, newUTF8(methodDesc)); -++ result = new Item(index++, key2); -++ put(result); -++ } -++ return result; -++ } -++ -++ /** -++ * Adds a method type reference to the constant pool of the class being -++ * build. Does nothing if the constant pool already contains a similar item. -++ * This method is intended for {@link Attribute} sub classes, and is -++ * normally not needed by class generators or adapters. -++ * -++ * @param methodDesc -++ * method descriptor of the method type. -++ * @return the index of a new or already existing method type reference -++ * item. -++ */ -++ public int newMethodType(final String methodDesc) { -++ return newMethodTypeItem(methodDesc).index; -++ } -++ -++ /** -++ * Adds a handle to the constant pool of the class being build. Does nothing -++ * if the constant pool already contains a similar item. This method is -++ * intended for {@link Attribute} sub classes, and is normally not needed by -++ * class generators or adapters. -++ * -++ * @param tag -++ * the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, -++ * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, -++ * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, -++ * {@link Opcodes#H_INVOKESTATIC}, -++ * {@link Opcodes#H_INVOKESPECIAL}, -++ * {@link Opcodes#H_NEWINVOKESPECIAL} or -++ * {@link Opcodes#H_INVOKEINTERFACE}. -++ * @param owner -++ * the internal name of the field or method owner class. -++ * @param name -++ * the name of the field or method. -++ * @param desc -++ * the descriptor of the field or method. -++ * @return a new or an already existing method type reference item. -++ */ -++ Item newHandleItem(final int tag, final String owner, final String name, -++ final String desc) { -++ key4.set(HANDLE_BASE + tag, owner, name, desc); -++ Item result = get(key4); -++ if (result == null) { -++ if (tag <= Opcodes.H_PUTSTATIC) { -++ put112(HANDLE, tag, newField(owner, name, desc)); -++ } else { -++ put112(HANDLE, -++ tag, -++ newMethod(owner, name, desc, -++ tag == Opcodes.H_INVOKEINTERFACE)); -++ } -++ result = new Item(index++, key4); -++ put(result); -++ } -++ return result; -++ } -++ -++ /** -++ * Adds a handle to the constant pool of the class being build. Does nothing -++ * if the constant pool already contains a similar item. This method is -++ * intended for {@link Attribute} sub classes, and is normally not needed by -++ * class generators or adapters. -++ * -++ * @param tag -++ * the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, -++ * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, -++ * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, -++ * {@link Opcodes#H_INVOKESTATIC}, -++ * {@link Opcodes#H_INVOKESPECIAL}, -++ * {@link Opcodes#H_NEWINVOKESPECIAL} or -++ * {@link Opcodes#H_INVOKEINTERFACE}. -++ * @param owner -++ * the internal name of the field or method owner class. -++ * @param name -++ * the name of the field or method. -++ * @param desc -++ * the descriptor of the field or method. -++ * @return the index of a new or already existing method type reference -++ * item. -++ */ -++ public int newHandle(final int tag, final String owner, final String name, -++ final String desc) { -++ return newHandleItem(tag, owner, name, desc).index; -++ } -++ -++ /** -++ * Adds an invokedynamic reference to the constant pool of the class being -++ * build. Does nothing if the constant pool already contains a similar item. -++ * This method is intended for {@link Attribute} sub classes, and is -++ * normally not needed by class generators or adapters. -++ * -++ * @param name -++ * name of the invoked method. -++ * @param desc -++ * descriptor of the invoke method. -++ * @param bsm -++ * the bootstrap method. -++ * @param bsmArgs -++ * the bootstrap method constant arguments. -++ * -++ * @return a new or an already existing invokedynamic type reference item. -++ */ -++ Item newInvokeDynamicItem(final String name, final String desc, -++ final Handle bsm, final Object... bsmArgs) { -++ // cache for performance -++ ByteVector bootstrapMethods = this.bootstrapMethods; -++ if (bootstrapMethods == null) { -++ bootstrapMethods = this.bootstrapMethods = new ByteVector(); -++ } -++ -++ int position = bootstrapMethods.length; // record current position -++ -++ int hashCode = bsm.hashCode(); -++ bootstrapMethods.putShort(newHandle(bsm.tag, bsm.owner, bsm.name, -++ bsm.desc)); -++ -++ int argsLength = bsmArgs.length; -++ bootstrapMethods.putShort(argsLength); -++ -++ for (int i = 0; i < argsLength; i++) { -++ Object bsmArg = bsmArgs[i]; -++ hashCode ^= bsmArg.hashCode(); -++ bootstrapMethods.putShort(newConst(bsmArg)); -++ } -++ -++ byte[] data = bootstrapMethods.data; -++ int length = (1 + 1 + argsLength) << 1; // (bsm + argCount + arguments) -++ hashCode &= 0x7FFFFFFF; -++ Item result = items[hashCode % items.length]; -++ loop: while (result != null) { -++ if (result.type != BSM || result.hashCode != hashCode) { -++ result = result.next; -++ continue; -++ } -++ -++ // because the data encode the size of the argument -++ // we don't need to test if these size are equals -++ int resultPosition = result.intVal; -++ for (int p = 0; p < length; p++) { -++ if (data[position + p] != data[resultPosition + p]) { -++ result = result.next; -++ continue loop; -++ } -++ } -++ break; -++ } -++ -++ int bootstrapMethodIndex; -++ if (result != null) { -++ bootstrapMethodIndex = result.index; -++ bootstrapMethods.length = position; // revert to old position -++ } else { -++ bootstrapMethodIndex = bootstrapMethodsCount++; -++ result = new Item(bootstrapMethodIndex); -++ result.set(position, hashCode); -++ put(result); -++ } -++ -++ // now, create the InvokeDynamic constant -++ key3.set(name, desc, bootstrapMethodIndex); -++ result = get(key3); -++ if (result == null) { -++ put122(INDY, bootstrapMethodIndex, newNameType(name, desc)); -++ result = new Item(index++, key3); -++ put(result); -++ } -++ return result; -++ } -++ -++ /** -++ * Adds an invokedynamic reference to the constant pool of the class being -++ * build. Does nothing if the constant pool already contains a similar item. -++ * This method is intended for {@link Attribute} sub classes, and is -++ * normally not needed by class generators or adapters. -++ * -++ * @param name -++ * name of the invoked method. -++ * @param desc -++ * descriptor of the invoke method. -++ * @param bsm -++ * the bootstrap method. -++ * @param bsmArgs -++ * the bootstrap method constant arguments. -++ * -++ * @return the index of a new or already existing invokedynamic reference -++ * item. -++ */ -++ public int newInvokeDynamic(final String name, final String desc, -++ final Handle bsm, final Object... bsmArgs) { -++ return newInvokeDynamicItem(name, desc, bsm, bsmArgs).index; -++ } -++ -++ /** -++ * Adds a field reference to the constant pool of the class being build. -++ * Does nothing if the constant pool already contains a similar item. -++ * -++ * @param owner -++ * the internal name of the field's owner class. -++ * @param name -++ * the field's name. -++ * @param desc -++ * the field's descriptor. -++ * @return a new or already existing field reference item. -++ */ -++ Item newFieldItem(final String owner, final String name, final String desc) { -++ key3.set(FIELD, owner, name, desc); -++ Item result = get(key3); -++ if (result == null) { -++ put122(FIELD, newClass(owner), newNameType(name, desc)); -++ result = new Item(index++, key3); -++ put(result); -++ } -++ return result; -++ } -++ -++ /** -++ * Adds a field reference to the constant pool of the class being build. -++ * Does nothing if the constant pool already contains a similar item. -++ * This method is intended for {@link Attribute} sub classes, and is -++ * normally not needed by class generators or adapters. -++ * -++ * @param owner -++ * the internal name of the field's owner class. -++ * @param name -++ * the field's name. -++ * @param desc -++ * the field's descriptor. -++ * @return the index of a new or already existing field reference item. -++ */ -++ public int newField(final String owner, final String name, final String desc) { -++ return newFieldItem(owner, name, desc).index; -++ } -++ -++ /** -++ * Adds a method reference to the constant pool of the class being build. -++ * Does nothing if the constant pool already contains a similar item. -++ * -++ * @param owner -++ * the internal name of the method's owner class. -++ * @param name -++ * the method's name. -++ * @param desc -++ * the method's descriptor. -++ * @param itf -++ * true if owner is an interface. -++ * @return a new or already existing method reference item. -++ */ -++ Item newMethodItem(final String owner, final String name, -++ final String desc, final boolean itf) { -++ int type = itf ? IMETH : METH; -++ key3.set(type, owner, name, desc); -++ Item result = get(key3); -++ if (result == null) { -++ put122(type, newClass(owner), newNameType(name, desc)); -++ result = new Item(index++, key3); -++ put(result); -++ } -++ return result; -++ } -++ -++ /** -++ * Adds a method reference to the constant pool of the class being build. -++ * Does nothing if the constant pool already contains a similar item. -++ * This method is intended for {@link Attribute} sub classes, and is -++ * normally not needed by class generators or adapters. -++ * -++ * @param owner -++ * the internal name of the method's owner class. -++ * @param name -++ * the method's name. -++ * @param desc -++ * the method's descriptor. -++ * @param itf -++ * true if owner is an interface. -++ * @return the index of a new or already existing method reference item. -++ */ -++ public int newMethod(final String owner, final String name, -++ final String desc, final boolean itf) { -++ return newMethodItem(owner, name, desc, itf).index; -++ } -++ -++ /** -++ * Adds an integer to the constant pool of the class being build. Does -++ * nothing if the constant pool already contains a similar item. -++ * -++ * @param value -++ * the int value. -++ * @return a new or already existing int item. -++ */ -++ Item newInteger(final int value) { -++ key.set(value); -++ Item result = get(key); -++ if (result == null) { -++ pool.putByte(INT).putInt(value); -++ result = new Item(index++, key); -++ put(result); -++ } -++ return result; -++ } -++ -++ /** -++ * Adds a float to the constant pool of the class being build. Does nothing -++ * if the constant pool already contains a similar item. -++ * -++ * @param value -++ * the float value. -++ * @return a new or already existing float item. -++ */ -++ Item newFloat(final float value) { -++ key.set(value); -++ Item result = get(key); -++ if (result == null) { -++ pool.putByte(FLOAT).putInt(key.intVal); -++ result = new Item(index++, key); -++ put(result); -++ } -++ return result; -++ } -++ -++ /** -++ * Adds a long to the constant pool of the class being build. Does nothing -++ * if the constant pool already contains a similar item. -++ * -++ * @param value -++ * the long value. -++ * @return a new or already existing long item. -++ */ -++ Item newLong(final long value) { -++ key.set(value); -++ Item result = get(key); -++ if (result == null) { -++ pool.putByte(LONG).putLong(value); -++ result = new Item(index, key); -++ index += 2; -++ put(result); -++ } -++ return result; -++ } -++ -++ /** -++ * Adds a double to the constant pool of the class being build. Does nothing -++ * if the constant pool already contains a similar item. -++ * -++ * @param value -++ * the double value. -++ * @return a new or already existing double item. -++ */ -++ Item newDouble(final double value) { -++ key.set(value); -++ Item result = get(key); -++ if (result == null) { -++ pool.putByte(DOUBLE).putLong(key.longVal); -++ result = new Item(index, key); -++ index += 2; -++ put(result); -++ } -++ return result; -++ } -++ -++ /** -++ * Adds a string to the constant pool of the class being build. Does nothing -++ * if the constant pool already contains a similar item. -++ * -++ * @param value -++ * the String value. -++ * @return a new or already existing string item. -++ */ -++ private Item newString(final String value) { -++ key2.set(STR, value, null, null); -++ Item result = get(key2); -++ if (result == null) { -++ pool.put12(STR, newUTF8(value)); -++ result = new Item(index++, key2); -++ put(result); -++ } -++ return result; -++ } -++ -++ /** -++ * Adds a name and type to the constant pool of the class being build. Does -++ * nothing if the constant pool already contains a similar item. This -++ * method is intended for {@link Attribute} sub classes, and is normally not -++ * needed by class generators or adapters. -++ * -++ * @param name -++ * a name. -++ * @param desc -++ * a type descriptor. -++ * @return the index of a new or already existing name and type item. -++ */ -++ public int newNameType(final String name, final String desc) { -++ return newNameTypeItem(name, desc).index; -++ } -++ -++ /** -++ * Adds a name and type to the constant pool of the class being build. Does -++ * nothing if the constant pool already contains a similar item. -++ * -++ * @param name -++ * a name. -++ * @param desc -++ * a type descriptor. -++ * @return a new or already existing name and type item. -++ */ -++ Item newNameTypeItem(final String name, final String desc) { -++ key2.set(NAME_TYPE, name, desc, null); -++ Item result = get(key2); -++ if (result == null) { -++ put122(NAME_TYPE, newUTF8(name), newUTF8(desc)); -++ result = new Item(index++, key2); -++ put(result); -++ } -++ return result; -++ } -++ -++ /** -++ * Adds the given internal name to {@link #typeTable} and returns its index. -++ * Does nothing if the type table already contains this internal name. -++ * -++ * @param type -++ * the internal name to be added to the type table. -++ * @return the index of this internal name in the type table. -++ */ -++ int addType(final String type) { -++ key.set(TYPE_NORMAL, type, null, null); -++ Item result = get(key); -++ if (result == null) { -++ result = addType(key); -++ } -++ return result.index; -++ } -++ -++ /** -++ * Adds the given "uninitialized" type to {@link #typeTable} and returns its -++ * index. This method is used for UNINITIALIZED types, made of an internal -++ * name and a bytecode offset. -++ * -++ * @param type -++ * the internal name to be added to the type table. -++ * @param offset -++ * the bytecode offset of the NEW instruction that created this -++ * UNINITIALIZED type value. -++ * @return the index of this internal name in the type table. -++ */ -++ int addUninitializedType(final String type, final int offset) { -++ key.type = TYPE_UNINIT; -++ key.intVal = offset; -++ key.strVal1 = type; -++ key.hashCode = 0x7FFFFFFF & (TYPE_UNINIT + type.hashCode() + offset); -++ Item result = get(key); -++ if (result == null) { -++ result = addType(key); -++ } -++ return result.index; -++ } -++ -++ /** -++ * Adds the given Item to {@link #typeTable}. -++ * -++ * @param item -++ * the value to be added to the type table. -++ * @return the added Item, which a new Item instance with the same value as -++ * the given Item. -++ */ -++ private Item addType(final Item item) { -++ ++typeCount; -++ Item result = new Item(typeCount, key); -++ put(result); -++ if (typeTable == null) { -++ typeTable = new Item[16]; -++ } -++ if (typeCount == typeTable.length) { -++ Item[] newTable = new Item[2 * typeTable.length]; -++ System.arraycopy(typeTable, 0, newTable, 0, typeTable.length); -++ typeTable = newTable; -++ } -++ typeTable[typeCount] = result; -++ return result; -++ } -++ -++ /** -++ * Returns the index of the common super type of the two given types. This -++ * method calls {@link #getCommonSuperClass} and caches the result in the -++ * {@link #items} hash table to speedup future calls with the same -++ * parameters. -++ * -++ * @param type1 -++ * index of an internal name in {@link #typeTable}. -++ * @param type2 -++ * index of an internal name in {@link #typeTable}. -++ * @return the index of the common super type of the two given types. -++ */ -++ int getMergedType(final int type1, final int type2) { -++ key2.type = TYPE_MERGED; -++ key2.longVal = type1 | (((long) type2) << 32); -++ key2.hashCode = 0x7FFFFFFF & (TYPE_MERGED + type1 + type2); -++ Item result = get(key2); -++ if (result == null) { -++ String t = typeTable[type1].strVal1; -++ String u = typeTable[type2].strVal1; -++ key2.intVal = addType(getCommonSuperClass(t, u)); -++ result = new Item((short) 0, key2); -++ put(result); -++ } -++ return result.intVal; -++ } -++ -++ /** -++ * Returns the common super type of the two given types. The default -++ * implementation of this method loads the two given classes and uses -++ * the java.lang.Class methods to find the common super class. It can be -++ * overridden to compute this common super type in other ways, in particular -++ * without actually loading any class, or to take into account the class -++ * that is currently being generated by this ClassWriter, which can of -++ * course not be loaded since it is under construction. -++ * -++ * @param type1 -++ * the internal name of a class. -++ * @param type2 -++ * the internal name of another class. -++ * @return the internal name of the common super class of the two given -++ * classes. -++ */ -++ protected String getCommonSuperClass(final String type1, final String type2) { -++ Class c, d; -++ ClassLoader classLoader = getClass().getClassLoader(); -++ try { -++ c = Class.forName(type1.replace('/', '.'), false, classLoader); -++ d = Class.forName(type2.replace('/', '.'), false, classLoader); -++ } catch (Exception e) { -++ throw new RuntimeException(e.toString()); -++ } -++ if (c.isAssignableFrom(d)) { -++ return type1; -++ } -++ if (d.isAssignableFrom(c)) { -++ return type2; -++ } -++ if (c.isInterface() || d.isInterface()) { -++ return "java/lang/Object"; -++ } else { -++ do { -++ c = c.getSuperclass(); -++ } while (!c.isAssignableFrom(d)); -++ return c.getName().replace('.', '/'); -++ } -++ } -++ -++ /** -++ * Returns the constant pool's hash table item which is equal to the given -++ * item. -++ * -++ * @param key -++ * a constant pool item. -++ * @return the constant pool's hash table item which is equal to the given -++ * item, or null if there is no such item. -++ */ -++ private Item get(final Item key) { -++ Item i = items[key.hashCode % items.length]; -++ while (i != null && (i.type != key.type || !key.isEqualTo(i))) { -++ i = i.next; -++ } -++ return i; -++ } -++ -++ /** -++ * Puts the given item in the constant pool's hash table. The hash table -++ * must not already contains this item. -++ * -++ * @param i -++ * the item to be added to the constant pool's hash table. -++ */ -++ private void put(final Item i) { -++ if (index + typeCount > threshold) { -++ int ll = items.length; -++ int nl = ll * 2 + 1; -++ Item[] newItems = new Item[nl]; -++ for (int l = ll - 1; l >= 0; --l) { -++ Item j = items[l]; -++ while (j != null) { -++ int index = j.hashCode % newItems.length; -++ Item k = j.next; -++ j.next = newItems[index]; -++ newItems[index] = j; -++ j = k; -++ } -++ } -++ items = newItems; -++ threshold = (int) (nl * 0.75); -++ } -++ int index = i.hashCode % items.length; -++ i.next = items[index]; -++ items[index] = i; -++ } -++ -++ /** -++ * Puts one byte and two shorts into the constant pool. -++ * -++ * @param b -++ * a byte. -++ * @param s1 -++ * a short. -++ * @param s2 -++ * another short. -++ */ -++ private void put122(final int b, final int s1, final int s2) { -++ pool.put12(b, s1).putShort(s2); -++ } -++ -++ /** -++ * Puts two bytes and one short into the constant pool. -++ * -++ * @param b1 -++ * a byte. -++ * @param b2 -++ * another byte. -++ * @param s -++ * a short. -++ */ -++ private void put112(final int b1, final int b2, final int s) { -++ pool.put11(b1, b2).putShort(s); -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/Context.java b/contrib/asm/src/org/objectweb/asm/Context.java -+new file mode 100644 -+index 0000000..363b34c -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/Context.java -+@@ -0,0 +1,145 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++ -++package org.objectweb.asm; -++ -++/** -++ * Information about a class being parsed in a {@link ClassReader}. -++ * -++ * @author Eric Bruneton -++ */ -++class Context { -++ -++ /** -++ * Prototypes of the attributes that must be parsed for this class. -++ */ -++ Attribute[] attrs; -++ -++ /** -++ * The {@link ClassReader} option flags for the parsing of this class. -++ */ -++ int flags; -++ -++ /** -++ * The buffer used to read strings. -++ */ -++ char[] buffer; -++ -++ /** -++ * The start index of each bootstrap method. -++ */ -++ int[] bootstrapMethods; -++ -++ /** -++ * The access flags of the method currently being parsed. -++ */ -++ int access; -++ -++ /** -++ * The name of the method currently being parsed. -++ */ -++ String name; -++ -++ /** -++ * The descriptor of the method currently being parsed. -++ */ -++ String desc; -++ -++ /** -++ * The label objects, indexed by bytecode offset, of the method currently -++ * being parsed (only bytecode offsets for which a label is needed have a -++ * non null associated Label object). -++ */ -++ Label[] labels; -++ -++ /** -++ * The target of the type annotation currently being parsed. -++ */ -++ int typeRef; -++ -++ /** -++ * The path of the type annotation currently being parsed. -++ */ -++ TypePath typePath; -++ -++ /** -++ * The offset of the latest stack map frame that has been parsed. -++ */ -++ int offset; -++ -++ /** -++ * The labels corresponding to the start of the local variable ranges in the -++ * local variable type annotation currently being parsed. -++ */ -++ Label[] start; -++ -++ /** -++ * The labels corresponding to the end of the local variable ranges in the -++ * local variable type annotation currently being parsed. -++ */ -++ Label[] end; -++ -++ /** -++ * The local variable indices for each local variable range in the local -++ * variable type annotation currently being parsed. -++ */ -++ int[] index; -++ -++ /** -++ * The encoding of the latest stack map frame that has been parsed. -++ */ -++ int mode; -++ -++ /** -++ * The number of locals in the latest stack map frame that has been parsed. -++ */ -++ int localCount; -++ -++ /** -++ * The number locals in the latest stack map frame that has been parsed, -++ * minus the number of locals in the previous frame. -++ */ -++ int localDiff; -++ -++ /** -++ * The local values of the latest stack map frame that has been parsed. -++ */ -++ Object[] local; -++ -++ /** -++ * The stack size of the latest stack map frame that has been parsed. -++ */ -++ int stackCount; -++ -++ /** -++ * The stack values of the latest stack map frame that has been parsed. -++ */ -++ Object[] stack; -++} -+\ No newline at end of file -+diff --git a/contrib/asm/src/org/objectweb/asm/Edge.java b/contrib/asm/src/org/objectweb/asm/Edge.java -+new file mode 100644 -+index 0000000..4e87cba -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/Edge.java -+@@ -0,0 +1,75 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * An edge in the control flow graph of a method body. See {@link Label Label}. -++ * -++ * @author Eric Bruneton -++ */ -++class Edge { -++ -++ /** -++ * Denotes a normal control flow graph edge. -++ */ -++ static final int NORMAL = 0; -++ -++ /** -++ * Denotes a control flow graph edge corresponding to an exception handler. -++ * More precisely any {@link Edge} whose {@link #info} is strictly positive -++ * corresponds to an exception handler. The actual value of {@link #info} is -++ * the index, in the {@link ClassWriter} type table, of the exception that -++ * is catched. -++ */ -++ static final int EXCEPTION = 0x7FFFFFFF; -++ -++ /** -++ * Information about this control flow graph edge. If -++ * {@link ClassWriter#COMPUTE_MAXS} is used this field is the (relative) -++ * stack size in the basic block from which this edge originates. This size -++ * is equal to the stack size at the "jump" instruction to which this edge -++ * corresponds, relatively to the stack size at the beginning of the -++ * originating basic block. If {@link ClassWriter#COMPUTE_FRAMES} is used, -++ * this field is the kind of this control flow graph edge (i.e. NORMAL or -++ * EXCEPTION). -++ */ -++ int info; -++ -++ /** -++ * The successor block of the basic block from which this edge originates. -++ */ -++ Label successor; -++ -++ /** -++ * The next edge in the list of successors of the originating basic block. -++ * See {@link Label#successors successors}. -++ */ -++ Edge next; -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/FieldVisitor.java b/contrib/asm/src/org/objectweb/asm/FieldVisitor.java -+new file mode 100644 -+index 0000000..2372e4c -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/FieldVisitor.java -+@@ -0,0 +1,150 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * A visitor to visit a Java field. The methods of this class must be called in -++ * the following order: ( visitAnnotation | -++ * visitTypeAnnotation | visitAttribute )* visitEnd. -++ * -++ * @author Eric Bruneton -++ */ -++public abstract class FieldVisitor { -++ -++ /** -++ * The ASM API version implemented by this visitor. The value of this field -++ * must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -++ */ -++ protected final int api; -++ -++ /** -++ * The field visitor to which this visitor must delegate method calls. May -++ * be null. -++ */ -++ protected FieldVisitor fv; -++ -++ /** -++ * Constructs a new {@link FieldVisitor}. -++ * -++ * @param api -++ * the ASM API version implemented by this visitor. Must be one -++ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -++ */ -++ public FieldVisitor(final int api) { -++ this(api, null); -++ } -++ -++ /** -++ * Constructs a new {@link FieldVisitor}. -++ * -++ * @param api -++ * the ASM API version implemented by this visitor. Must be one -++ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -++ * @param fv -++ * the field visitor to which this visitor must delegate method -++ * calls. May be null. -++ */ -++ public FieldVisitor(final int api, final FieldVisitor fv) { -++ if (api != Opcodes.ASM4 && api != Opcodes.ASM5) { -++ throw new IllegalArgumentException(); -++ } -++ this.api = api; -++ this.fv = fv; -++ } -++ -++ /** -++ * Visits an annotation of the field. -++ * -++ * @param desc -++ * the class descriptor of the annotation class. -++ * @param visible -++ * true if the annotation is visible at runtime. -++ * @return a visitor to visit the annotation values, or null if -++ * this visitor is not interested in visiting this annotation. -++ */ -++ public AnnotationVisitor visitAnnotation(String desc, boolean visible) { -++ if (fv != null) { -++ return fv.visitAnnotation(desc, visible); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits an annotation on the type of the field. -++ * -++ * @param typeRef -++ * a reference to the annotated type. The sort of this type -++ * reference must be {@link TypeReference#FIELD FIELD}. See -++ * {@link TypeReference}. -++ * @param typePath -++ * the path to the annotated type argument, wildcard bound, array -++ * element type, or static inner type within 'typeRef'. May be -++ * null if the annotation targets 'typeRef' as a whole. -++ * @param desc -++ * the class descriptor of the annotation class. -++ * @param visible -++ * true if the annotation is visible at runtime. -++ * @return a visitor to visit the annotation values, or null if -++ * this visitor is not interested in visiting this annotation. -++ */ -++ public AnnotationVisitor visitTypeAnnotation(int typeRef, -++ TypePath typePath, String desc, boolean visible) { -++ if (api < Opcodes.ASM5) { -++ throw new RuntimeException(); -++ } -++ if (fv != null) { -++ return fv.visitTypeAnnotation(typeRef, typePath, desc, visible); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits a non standard attribute of the field. -++ * -++ * @param attr -++ * an attribute. -++ */ -++ public void visitAttribute(Attribute attr) { -++ if (fv != null) { -++ fv.visitAttribute(attr); -++ } -++ } -++ -++ /** -++ * Visits the end of the field. This method, which is the last one to be -++ * called, is used to inform the visitor that all the annotations and -++ * attributes of the field have been visited. -++ */ -++ public void visitEnd() { -++ if (fv != null) { -++ fv.visitEnd(); -++ } -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/FieldWriter.java b/contrib/asm/src/org/objectweb/asm/FieldWriter.java -+new file mode 100644 -+index 0000000..84d92aa -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/FieldWriter.java -+@@ -0,0 +1,329 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * An {@link FieldVisitor} that generates Java fields in bytecode form. -++ * -++ * @author Eric Bruneton -++ */ -++final class FieldWriter extends FieldVisitor { -++ -++ /** -++ * The class writer to which this field must be added. -++ */ -++ private final ClassWriter cw; -++ -++ /** -++ * Access flags of this field. -++ */ -++ private final int access; -++ -++ /** -++ * The index of the constant pool item that contains the name of this -++ * method. -++ */ -++ private final int name; -++ -++ /** -++ * The index of the constant pool item that contains the descriptor of this -++ * field. -++ */ -++ private final int desc; -++ -++ /** -++ * The index of the constant pool item that contains the signature of this -++ * field. -++ */ -++ private int signature; -++ -++ /** -++ * The index of the constant pool item that contains the constant value of -++ * this field. -++ */ -++ private int value; -++ -++ /** -++ * The runtime visible annotations of this field. May be null. -++ */ -++ private AnnotationWriter anns; -++ -++ /** -++ * The runtime invisible annotations of this field. May be null. -++ */ -++ private AnnotationWriter ianns; -++ -++ /** -++ * The runtime visible type annotations of this field. May be null. -++ */ -++ private AnnotationWriter tanns; -++ -++ /** -++ * The runtime invisible type annotations of this field. May be -++ * null. -++ */ -++ private AnnotationWriter itanns; -++ -++ /** -++ * The non standard attributes of this field. May be null. -++ */ -++ private Attribute attrs; -++ -++ // ------------------------------------------------------------------------ -++ // Constructor -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Constructs a new {@link FieldWriter}. -++ * -++ * @param cw -++ * the class writer to which this field must be added. -++ * @param access -++ * the field's access flags (see {@link Opcodes}). -++ * @param name -++ * the field's name. -++ * @param desc -++ * the field's descriptor (see {@link Type}). -++ * @param signature -++ * the field's signature. May be null. -++ * @param value -++ * the field's constant value. May be null. -++ */ -++ FieldWriter(final ClassWriter cw, final int access, final String name, -++ final String desc, final String signature, final Object value) { -++ super(Opcodes.ASM5); -++ if (cw.firstField == null) { -++ cw.firstField = this; -++ } else { -++ cw.lastField.fv = this; -++ } -++ cw.lastField = this; -++ this.cw = cw; -++ this.access = access; -++ this.name = cw.newUTF8(name); -++ this.desc = cw.newUTF8(desc); -++ if (ClassReader.SIGNATURES && signature != null) { -++ this.signature = cw.newUTF8(signature); -++ } -++ if (value != null) { -++ this.value = cw.newConstItem(value).index; -++ } -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Implementation of the FieldVisitor abstract class -++ // ------------------------------------------------------------------------ -++ -++ @Override -++ public AnnotationVisitor visitAnnotation(final String desc, -++ final boolean visible) { -++ if (!ClassReader.ANNOTATIONS) { -++ return null; -++ } -++ ByteVector bv = new ByteVector(); -++ // write type, and reserve space for values count -++ bv.putShort(cw.newUTF8(desc)).putShort(0); -++ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); -++ if (visible) { -++ aw.next = anns; -++ anns = aw; -++ } else { -++ aw.next = ianns; -++ ianns = aw; -++ } -++ return aw; -++ } -++ -++ @Override -++ public AnnotationVisitor visitTypeAnnotation(final int typeRef, -++ final TypePath typePath, final String desc, final boolean visible) { -++ if (!ClassReader.ANNOTATIONS) { -++ return null; -++ } -++ ByteVector bv = new ByteVector(); -++ // write target_type and target_info -++ AnnotationWriter.putTarget(typeRef, typePath, bv); -++ // write type, and reserve space for values count -++ bv.putShort(cw.newUTF8(desc)).putShort(0); -++ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, -++ bv.length - 2); -++ if (visible) { -++ aw.next = tanns; -++ tanns = aw; -++ } else { -++ aw.next = itanns; -++ itanns = aw; -++ } -++ return aw; -++ } -++ -++ @Override -++ public void visitAttribute(final Attribute attr) { -++ attr.next = attrs; -++ attrs = attr; -++ } -++ -++ @Override -++ public void visitEnd() { -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Utility methods -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Returns the size of this field. -++ * -++ * @return the size of this field. -++ */ -++ int getSize() { -++ int size = 8; -++ if (value != 0) { -++ cw.newUTF8("ConstantValue"); -++ size += 8; -++ } -++ if ((access & Opcodes.ACC_SYNTHETIC) != 0) { -++ if ((cw.version & 0xFFFF) < Opcodes.V1_5 -++ || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { -++ cw.newUTF8("Synthetic"); -++ size += 6; -++ } -++ } -++ if ((access & Opcodes.ACC_DEPRECATED) != 0) { -++ cw.newUTF8("Deprecated"); -++ size += 6; -++ } -++ if (ClassReader.SIGNATURES && signature != 0) { -++ cw.newUTF8("Signature"); -++ size += 8; -++ } -++ if (ClassReader.ANNOTATIONS && anns != null) { -++ cw.newUTF8("RuntimeVisibleAnnotations"); -++ size += 8 + anns.getSize(); -++ } -++ if (ClassReader.ANNOTATIONS && ianns != null) { -++ cw.newUTF8("RuntimeInvisibleAnnotations"); -++ size += 8 + ianns.getSize(); -++ } -++ if (ClassReader.ANNOTATIONS && tanns != null) { -++ cw.newUTF8("RuntimeVisibleTypeAnnotations"); -++ size += 8 + tanns.getSize(); -++ } -++ if (ClassReader.ANNOTATIONS && itanns != null) { -++ cw.newUTF8("RuntimeInvisibleTypeAnnotations"); -++ size += 8 + itanns.getSize(); -++ } -++ if (attrs != null) { -++ size += attrs.getSize(cw, null, 0, -1, -1); -++ } -++ return size; -++ } -++ -++ /** -++ * Puts the content of this field into the given byte vector. -++ * -++ * @param out -++ * where the content of this field must be put. -++ */ -++ void put(final ByteVector out) { -++ final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC; -++ int mask = Opcodes.ACC_DEPRECATED | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE -++ | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR); -++ out.putShort(access & ~mask).putShort(name).putShort(desc); -++ int attributeCount = 0; -++ if (value != 0) { -++ ++attributeCount; -++ } -++ if ((access & Opcodes.ACC_SYNTHETIC) != 0) { -++ if ((cw.version & 0xFFFF) < Opcodes.V1_5 -++ || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { -++ ++attributeCount; -++ } -++ } -++ if ((access & Opcodes.ACC_DEPRECATED) != 0) { -++ ++attributeCount; -++ } -++ if (ClassReader.SIGNATURES && signature != 0) { -++ ++attributeCount; -++ } -++ if (ClassReader.ANNOTATIONS && anns != null) { -++ ++attributeCount; -++ } -++ if (ClassReader.ANNOTATIONS && ianns != null) { -++ ++attributeCount; -++ } -++ if (ClassReader.ANNOTATIONS && tanns != null) { -++ ++attributeCount; -++ } -++ if (ClassReader.ANNOTATIONS && itanns != null) { -++ ++attributeCount; -++ } -++ if (attrs != null) { -++ attributeCount += attrs.getCount(); -++ } -++ out.putShort(attributeCount); -++ if (value != 0) { -++ out.putShort(cw.newUTF8("ConstantValue")); -++ out.putInt(2).putShort(value); -++ } -++ if ((access & Opcodes.ACC_SYNTHETIC) != 0) { -++ if ((cw.version & 0xFFFF) < Opcodes.V1_5 -++ || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { -++ out.putShort(cw.newUTF8("Synthetic")).putInt(0); -++ } -++ } -++ if ((access & Opcodes.ACC_DEPRECATED) != 0) { -++ out.putShort(cw.newUTF8("Deprecated")).putInt(0); -++ } -++ if (ClassReader.SIGNATURES && signature != 0) { -++ out.putShort(cw.newUTF8("Signature")); -++ out.putInt(2).putShort(signature); -++ } -++ if (ClassReader.ANNOTATIONS && anns != null) { -++ out.putShort(cw.newUTF8("RuntimeVisibleAnnotations")); -++ anns.put(out); -++ } -++ if (ClassReader.ANNOTATIONS && ianns != null) { -++ out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations")); -++ ianns.put(out); -++ } -++ if (ClassReader.ANNOTATIONS && tanns != null) { -++ out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations")); -++ tanns.put(out); -++ } -++ if (ClassReader.ANNOTATIONS && itanns != null) { -++ out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations")); -++ itanns.put(out); -++ } -++ if (attrs != null) { -++ attrs.put(cw, null, 0, -1, -1, out); -++ } -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/Frame.java b/contrib/asm/src/org/objectweb/asm/Frame.java -+new file mode 100644 -+index 0000000..1f6106f -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/Frame.java -+@@ -0,0 +1,1462 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * Information about the input and output stack map frames of a basic block. -++ * -++ * @author Eric Bruneton -++ */ -++final class Frame { -++ -++ /* -++ * Frames are computed in a two steps process: during the visit of each -++ * instruction, the state of the frame at the end of current basic block is -++ * updated by simulating the action of the instruction on the previous state -++ * of this so called "output frame". In visitMaxs, a fix point algorithm is -++ * used to compute the "input frame" of each basic block, i.e. the stack map -++ * frame at the beginning of the basic block, starting from the input frame -++ * of the first basic block (which is computed from the method descriptor), -++ * and by using the previously computed output frames to compute the input -++ * state of the other blocks. -++ * -++ * All output and input frames are stored as arrays of integers. Reference -++ * and array types are represented by an index into a type table (which is -++ * not the same as the constant pool of the class, in order to avoid adding -++ * unnecessary constants in the pool - not all computed frames will end up -++ * being stored in the stack map table). This allows very fast type -++ * comparisons. -++ * -++ * Output stack map frames are computed relatively to the input frame of the -++ * basic block, which is not yet known when output frames are computed. It -++ * is therefore necessary to be able to represent abstract types such as -++ * "the type at position x in the input frame locals" or "the type at -++ * position x from the top of the input frame stack" or even "the type at -++ * position x in the input frame, with y more (or less) array dimensions". -++ * This explains the rather complicated type format used in output frames. -++ * -++ * This format is the following: DIM KIND VALUE (4, 4 and 24 bits). DIM is a -++ * signed number of array dimensions (from -8 to 7). KIND is either BASE, -++ * LOCAL or STACK. BASE is used for types that are not relative to the input -++ * frame. LOCAL is used for types that are relative to the input local -++ * variable types. STACK is used for types that are relative to the input -++ * stack types. VALUE depends on KIND. For LOCAL types, it is an index in -++ * the input local variable types. For STACK types, it is a position -++ * relatively to the top of input frame stack. For BASE types, it is either -++ * one of the constants defined below, or for OBJECT and UNINITIALIZED -++ * types, a tag and an index in the type table. -++ * -++ * Output frames can contain types of any kind and with a positive or -++ * negative dimension (and even unassigned types, represented by 0 - which -++ * does not correspond to any valid type value). Input frames can only -++ * contain BASE types of positive or null dimension. In all cases the type -++ * table contains only internal type names (array type descriptors are -++ * forbidden - dimensions must be represented through the DIM field). -++ * -++ * The LONG and DOUBLE types are always represented by using two slots (LONG -++ * + TOP or DOUBLE + TOP), for local variable types as well as in the -++ * operand stack. This is necessary to be able to simulate DUPx_y -++ * instructions, whose effect would be dependent on the actual type values -++ * if types were always represented by a single slot in the stack (and this -++ * is not possible, since actual type values are not always known - cf LOCAL -++ * and STACK type kinds). -++ */ -++ -++ /** -++ * Mask to get the dimension of a frame type. This dimension is a signed -++ * integer between -8 and 7. -++ */ -++ static final int DIM = 0xF0000000; -++ -++ /** -++ * Constant to be added to a type to get a type with one more dimension. -++ */ -++ static final int ARRAY_OF = 0x10000000; -++ -++ /** -++ * Constant to be added to a type to get a type with one less dimension. -++ */ -++ static final int ELEMENT_OF = 0xF0000000; -++ -++ /** -++ * Mask to get the kind of a frame type. -++ * -++ * @see #BASE -++ * @see #LOCAL -++ * @see #STACK -++ */ -++ static final int KIND = 0xF000000; -++ -++ /** -++ * Flag used for LOCAL and STACK types. Indicates that if this type happens -++ * to be a long or double type (during the computations of input frames), -++ * then it must be set to TOP because the second word of this value has been -++ * reused to store other data in the basic block. Hence the first word no -++ * longer stores a valid long or double value. -++ */ -++ static final int TOP_IF_LONG_OR_DOUBLE = 0x800000; -++ -++ /** -++ * Mask to get the value of a frame type. -++ */ -++ static final int VALUE = 0x7FFFFF; -++ -++ /** -++ * Mask to get the kind of base types. -++ */ -++ static final int BASE_KIND = 0xFF00000; -++ -++ /** -++ * Mask to get the value of base types. -++ */ -++ static final int BASE_VALUE = 0xFFFFF; -++ -++ /** -++ * Kind of the types that are not relative to an input stack map frame. -++ */ -++ static final int BASE = 0x1000000; -++ -++ /** -++ * Base kind of the base reference types. The BASE_VALUE of such types is an -++ * index into the type table. -++ */ -++ static final int OBJECT = BASE | 0x700000; -++ -++ /** -++ * Base kind of the uninitialized base types. The BASE_VALUE of such types -++ * in an index into the type table (the Item at that index contains both an -++ * instruction offset and an internal class name). -++ */ -++ static final int UNINITIALIZED = BASE | 0x800000; -++ -++ /** -++ * Kind of the types that are relative to the local variable types of an -++ * input stack map frame. The value of such types is a local variable index. -++ */ -++ private static final int LOCAL = 0x2000000; -++ -++ /** -++ * Kind of the the types that are relative to the stack of an input stack -++ * map frame. The value of such types is a position relatively to the top of -++ * this stack. -++ */ -++ private static final int STACK = 0x3000000; -++ -++ /** -++ * The TOP type. This is a BASE type. -++ */ -++ static final int TOP = BASE | 0; -++ -++ /** -++ * The BOOLEAN type. This is a BASE type mainly used for array types. -++ */ -++ static final int BOOLEAN = BASE | 9; -++ -++ /** -++ * The BYTE type. This is a BASE type mainly used for array types. -++ */ -++ static final int BYTE = BASE | 10; -++ -++ /** -++ * The CHAR type. This is a BASE type mainly used for array types. -++ */ -++ static final int CHAR = BASE | 11; -++ -++ /** -++ * The SHORT type. This is a BASE type mainly used for array types. -++ */ -++ static final int SHORT = BASE | 12; -++ -++ /** -++ * The INTEGER type. This is a BASE type. -++ */ -++ static final int INTEGER = BASE | 1; -++ -++ /** -++ * The FLOAT type. This is a BASE type. -++ */ -++ static final int FLOAT = BASE | 2; -++ -++ /** -++ * The DOUBLE type. This is a BASE type. -++ */ -++ static final int DOUBLE = BASE | 3; -++ -++ /** -++ * The LONG type. This is a BASE type. -++ */ -++ static final int LONG = BASE | 4; -++ -++ /** -++ * The NULL type. This is a BASE type. -++ */ -++ static final int NULL = BASE | 5; -++ -++ /** -++ * The UNINITIALIZED_THIS type. This is a BASE type. -++ */ -++ static final int UNINITIALIZED_THIS = BASE | 6; -++ -++ /** -++ * The stack size variation corresponding to each JVM instruction. This -++ * stack variation is equal to the size of the values produced by an -++ * instruction, minus the size of the values consumed by this instruction. -++ */ -++ static final int[] SIZE; -++ -++ /** -++ * Computes the stack size variation corresponding to each JVM instruction. -++ */ -++ static { -++ int i; -++ int[] b = new int[202]; -++ String s = "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDD" -++ + "CDCDEEEEEEEEEEEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCD" -++ + "CDCEEEEDDDDDDDCDCDCEFEFDDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFED" -++ + "DDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE"; -++ for (i = 0; i < b.length; ++i) { -++ b[i] = s.charAt(i) - 'E'; -++ } -++ SIZE = b; -++ -++ // code to generate the above string -++ // -++ // int NA = 0; // not applicable (unused opcode or variable size opcode) -++ // -++ // b = new int[] { -++ // 0, //NOP, // visitInsn -++ // 1, //ACONST_NULL, // - -++ // 1, //ICONST_M1, // - -++ // 1, //ICONST_0, // - -++ // 1, //ICONST_1, // - -++ // 1, //ICONST_2, // - -++ // 1, //ICONST_3, // - -++ // 1, //ICONST_4, // - -++ // 1, //ICONST_5, // - -++ // 2, //LCONST_0, // - -++ // 2, //LCONST_1, // - -++ // 1, //FCONST_0, // - -++ // 1, //FCONST_1, // - -++ // 1, //FCONST_2, // - -++ // 2, //DCONST_0, // - -++ // 2, //DCONST_1, // - -++ // 1, //BIPUSH, // visitIntInsn -++ // 1, //SIPUSH, // - -++ // 1, //LDC, // visitLdcInsn -++ // NA, //LDC_W, // - -++ // NA, //LDC2_W, // - -++ // 1, //ILOAD, // visitVarInsn -++ // 2, //LLOAD, // - -++ // 1, //FLOAD, // - -++ // 2, //DLOAD, // - -++ // 1, //ALOAD, // - -++ // NA, //ILOAD_0, // - -++ // NA, //ILOAD_1, // - -++ // NA, //ILOAD_2, // - -++ // NA, //ILOAD_3, // - -++ // NA, //LLOAD_0, // - -++ // NA, //LLOAD_1, // - -++ // NA, //LLOAD_2, // - -++ // NA, //LLOAD_3, // - -++ // NA, //FLOAD_0, // - -++ // NA, //FLOAD_1, // - -++ // NA, //FLOAD_2, // - -++ // NA, //FLOAD_3, // - -++ // NA, //DLOAD_0, // - -++ // NA, //DLOAD_1, // - -++ // NA, //DLOAD_2, // - -++ // NA, //DLOAD_3, // - -++ // NA, //ALOAD_0, // - -++ // NA, //ALOAD_1, // - -++ // NA, //ALOAD_2, // - -++ // NA, //ALOAD_3, // - -++ // -1, //IALOAD, // visitInsn -++ // 0, //LALOAD, // - -++ // -1, //FALOAD, // - -++ // 0, //DALOAD, // - -++ // -1, //AALOAD, // - -++ // -1, //BALOAD, // - -++ // -1, //CALOAD, // - -++ // -1, //SALOAD, // - -++ // -1, //ISTORE, // visitVarInsn -++ // -2, //LSTORE, // - -++ // -1, //FSTORE, // - -++ // -2, //DSTORE, // - -++ // -1, //ASTORE, // - -++ // NA, //ISTORE_0, // - -++ // NA, //ISTORE_1, // - -++ // NA, //ISTORE_2, // - -++ // NA, //ISTORE_3, // - -++ // NA, //LSTORE_0, // - -++ // NA, //LSTORE_1, // - -++ // NA, //LSTORE_2, // - -++ // NA, //LSTORE_3, // - -++ // NA, //FSTORE_0, // - -++ // NA, //FSTORE_1, // - -++ // NA, //FSTORE_2, // - -++ // NA, //FSTORE_3, // - -++ // NA, //DSTORE_0, // - -++ // NA, //DSTORE_1, // - -++ // NA, //DSTORE_2, // - -++ // NA, //DSTORE_3, // - -++ // NA, //ASTORE_0, // - -++ // NA, //ASTORE_1, // - -++ // NA, //ASTORE_2, // - -++ // NA, //ASTORE_3, // - -++ // -3, //IASTORE, // visitInsn -++ // -4, //LASTORE, // - -++ // -3, //FASTORE, // - -++ // -4, //DASTORE, // - -++ // -3, //AASTORE, // - -++ // -3, //BASTORE, // - -++ // -3, //CASTORE, // - -++ // -3, //SASTORE, // - -++ // -1, //POP, // - -++ // -2, //POP2, // - -++ // 1, //DUP, // - -++ // 1, //DUP_X1, // - -++ // 1, //DUP_X2, // - -++ // 2, //DUP2, // - -++ // 2, //DUP2_X1, // - -++ // 2, //DUP2_X2, // - -++ // 0, //SWAP, // - -++ // -1, //IADD, // - -++ // -2, //LADD, // - -++ // -1, //FADD, // - -++ // -2, //DADD, // - -++ // -1, //ISUB, // - -++ // -2, //LSUB, // - -++ // -1, //FSUB, // - -++ // -2, //DSUB, // - -++ // -1, //IMUL, // - -++ // -2, //LMUL, // - -++ // -1, //FMUL, // - -++ // -2, //DMUL, // - -++ // -1, //IDIV, // - -++ // -2, //LDIV, // - -++ // -1, //FDIV, // - -++ // -2, //DDIV, // - -++ // -1, //IREM, // - -++ // -2, //LREM, // - -++ // -1, //FREM, // - -++ // -2, //DREM, // - -++ // 0, //INEG, // - -++ // 0, //LNEG, // - -++ // 0, //FNEG, // - -++ // 0, //DNEG, // - -++ // -1, //ISHL, // - -++ // -1, //LSHL, // - -++ // -1, //ISHR, // - -++ // -1, //LSHR, // - -++ // -1, //IUSHR, // - -++ // -1, //LUSHR, // - -++ // -1, //IAND, // - -++ // -2, //LAND, // - -++ // -1, //IOR, // - -++ // -2, //LOR, // - -++ // -1, //IXOR, // - -++ // -2, //LXOR, // - -++ // 0, //IINC, // visitIincInsn -++ // 1, //I2L, // visitInsn -++ // 0, //I2F, // - -++ // 1, //I2D, // - -++ // -1, //L2I, // - -++ // -1, //L2F, // - -++ // 0, //L2D, // - -++ // 0, //F2I, // - -++ // 1, //F2L, // - -++ // 1, //F2D, // - -++ // -1, //D2I, // - -++ // 0, //D2L, // - -++ // -1, //D2F, // - -++ // 0, //I2B, // - -++ // 0, //I2C, // - -++ // 0, //I2S, // - -++ // -3, //LCMP, // - -++ // -1, //FCMPL, // - -++ // -1, //FCMPG, // - -++ // -3, //DCMPL, // - -++ // -3, //DCMPG, // - -++ // -1, //IFEQ, // visitJumpInsn -++ // -1, //IFNE, // - -++ // -1, //IFLT, // - -++ // -1, //IFGE, // - -++ // -1, //IFGT, // - -++ // -1, //IFLE, // - -++ // -2, //IF_ICMPEQ, // - -++ // -2, //IF_ICMPNE, // - -++ // -2, //IF_ICMPLT, // - -++ // -2, //IF_ICMPGE, // - -++ // -2, //IF_ICMPGT, // - -++ // -2, //IF_ICMPLE, // - -++ // -2, //IF_ACMPEQ, // - -++ // -2, //IF_ACMPNE, // - -++ // 0, //GOTO, // - -++ // 1, //JSR, // - -++ // 0, //RET, // visitVarInsn -++ // -1, //TABLESWITCH, // visiTableSwitchInsn -++ // -1, //LOOKUPSWITCH, // visitLookupSwitch -++ // -1, //IRETURN, // visitInsn -++ // -2, //LRETURN, // - -++ // -1, //FRETURN, // - -++ // -2, //DRETURN, // - -++ // -1, //ARETURN, // - -++ // 0, //RETURN, // - -++ // NA, //GETSTATIC, // visitFieldInsn -++ // NA, //PUTSTATIC, // - -++ // NA, //GETFIELD, // - -++ // NA, //PUTFIELD, // - -++ // NA, //INVOKEVIRTUAL, // visitMethodInsn -++ // NA, //INVOKESPECIAL, // - -++ // NA, //INVOKESTATIC, // - -++ // NA, //INVOKEINTERFACE, // - -++ // NA, //INVOKEDYNAMIC, // visitInvokeDynamicInsn -++ // 1, //NEW, // visitTypeInsn -++ // 0, //NEWARRAY, // visitIntInsn -++ // 0, //ANEWARRAY, // visitTypeInsn -++ // 0, //ARRAYLENGTH, // visitInsn -++ // NA, //ATHROW, // - -++ // 0, //CHECKCAST, // visitTypeInsn -++ // 0, //INSTANCEOF, // - -++ // -1, //MONITORENTER, // visitInsn -++ // -1, //MONITOREXIT, // - -++ // NA, //WIDE, // NOT VISITED -++ // NA, //MULTIANEWARRAY, // visitMultiANewArrayInsn -++ // -1, //IFNULL, // visitJumpInsn -++ // -1, //IFNONNULL, // - -++ // NA, //GOTO_W, // - -++ // NA, //JSR_W, // - -++ // }; -++ // for (i = 0; i < b.length; ++i) { -++ // System.err.print((char)('E' + b[i])); -++ // } -++ // System.err.println(); -++ } -++ -++ /** -++ * The label (i.e. basic block) to which these input and output stack map -++ * frames correspond. -++ */ -++ Label owner; -++ -++ /** -++ * The input stack map frame locals. -++ */ -++ int[] inputLocals; -++ -++ /** -++ * The input stack map frame stack. -++ */ -++ int[] inputStack; -++ -++ /** -++ * The output stack map frame locals. -++ */ -++ private int[] outputLocals; -++ -++ /** -++ * The output stack map frame stack. -++ */ -++ private int[] outputStack; -++ -++ /** -++ * Relative size of the output stack. The exact semantics of this field -++ * depends on the algorithm that is used. -++ * -++ * When only the maximum stack size is computed, this field is the size of -++ * the output stack relatively to the top of the input stack. -++ * -++ * When the stack map frames are completely computed, this field is the -++ * actual number of types in {@link #outputStack}. -++ */ -++ private int outputStackTop; -++ -++ /** -++ * Number of types that are initialized in the basic block. -++ * -++ * @see #initializations -++ */ -++ private int initializationCount; -++ -++ /** -++ * The types that are initialized in the basic block. A constructor -++ * invocation on an UNINITIALIZED or UNINITIALIZED_THIS type must replace -++ * every occurence of this type in the local variables and in the -++ * operand stack. This cannot be done during the first phase of the -++ * algorithm since, during this phase, the local variables and the operand -++ * stack are not completely computed. It is therefore necessary to store the -++ * types on which constructors are invoked in the basic block, in order to -++ * do this replacement during the second phase of the algorithm, where the -++ * frames are fully computed. Note that this array can contain types that -++ * are relative to input locals or to the input stack (see below for the -++ * description of the algorithm). -++ */ -++ private int[] initializations; -++ -++ /** -++ * Returns the output frame local variable type at the given index. -++ * -++ * @param local -++ * the index of the local that must be returned. -++ * @return the output frame local variable type at the given index. -++ */ -++ private int get(final int local) { -++ if (outputLocals == null || local >= outputLocals.length) { -++ // this local has never been assigned in this basic block, -++ // so it is still equal to its value in the input frame -++ return LOCAL | local; -++ } else { -++ int type = outputLocals[local]; -++ if (type == 0) { -++ // this local has never been assigned in this basic block, -++ // so it is still equal to its value in the input frame -++ type = outputLocals[local] = LOCAL | local; -++ } -++ return type; -++ } -++ } -++ -++ /** -++ * Sets the output frame local variable type at the given index. -++ * -++ * @param local -++ * the index of the local that must be set. -++ * @param type -++ * the value of the local that must be set. -++ */ -++ private void set(final int local, final int type) { -++ // creates and/or resizes the output local variables array if necessary -++ if (outputLocals == null) { -++ outputLocals = new int[10]; -++ } -++ int n = outputLocals.length; -++ if (local >= n) { -++ int[] t = new int[Math.max(local + 1, 2 * n)]; -++ System.arraycopy(outputLocals, 0, t, 0, n); -++ outputLocals = t; -++ } -++ // sets the local variable -++ outputLocals[local] = type; -++ } -++ -++ /** -++ * Pushes a new type onto the output frame stack. -++ * -++ * @param type -++ * the type that must be pushed. -++ */ -++ private void push(final int type) { -++ // creates and/or resizes the output stack array if necessary -++ if (outputStack == null) { -++ outputStack = new int[10]; -++ } -++ int n = outputStack.length; -++ if (outputStackTop >= n) { -++ int[] t = new int[Math.max(outputStackTop + 1, 2 * n)]; -++ System.arraycopy(outputStack, 0, t, 0, n); -++ outputStack = t; -++ } -++ // pushes the type on the output stack -++ outputStack[outputStackTop++] = type; -++ // updates the maximun height reached by the output stack, if needed -++ int top = owner.inputStackTop + outputStackTop; -++ if (top > owner.outputStackMax) { -++ owner.outputStackMax = top; -++ } -++ } -++ -++ /** -++ * Pushes a new type onto the output frame stack. -++ * -++ * @param cw -++ * the ClassWriter to which this label belongs. -++ * @param desc -++ * the descriptor of the type to be pushed. Can also be a method -++ * descriptor (in this case this method pushes its return type -++ * onto the output frame stack). -++ */ -++ private void push(final ClassWriter cw, final String desc) { -++ int type = type(cw, desc); -++ if (type != 0) { -++ push(type); -++ if (type == LONG || type == DOUBLE) { -++ push(TOP); -++ } -++ } -++ } -++ -++ /** -++ * Returns the int encoding of the given type. -++ * -++ * @param cw -++ * the ClassWriter to which this label belongs. -++ * @param desc -++ * a type descriptor. -++ * @return the int encoding of the given type. -++ */ -++ private static int type(final ClassWriter cw, final String desc) { -++ String t; -++ int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0; -++ switch (desc.charAt(index)) { -++ case 'V': -++ return 0; -++ case 'Z': -++ case 'C': -++ case 'B': -++ case 'S': -++ case 'I': -++ return INTEGER; -++ case 'F': -++ return FLOAT; -++ case 'J': -++ return LONG; -++ case 'D': -++ return DOUBLE; -++ case 'L': -++ // stores the internal name, not the descriptor! -++ t = desc.substring(index + 1, desc.length() - 1); -++ return OBJECT | cw.addType(t); -++ // case '[': -++ default: -++ // extracts the dimensions and the element type -++ int data; -++ int dims = index + 1; -++ while (desc.charAt(dims) == '[') { -++ ++dims; -++ } -++ switch (desc.charAt(dims)) { -++ case 'Z': -++ data = BOOLEAN; -++ break; -++ case 'C': -++ data = CHAR; -++ break; -++ case 'B': -++ data = BYTE; -++ break; -++ case 'S': -++ data = SHORT; -++ break; -++ case 'I': -++ data = INTEGER; -++ break; -++ case 'F': -++ data = FLOAT; -++ break; -++ case 'J': -++ data = LONG; -++ break; -++ case 'D': -++ data = DOUBLE; -++ break; -++ // case 'L': -++ default: -++ // stores the internal name, not the descriptor -++ t = desc.substring(dims + 1, desc.length() - 1); -++ data = OBJECT | cw.addType(t); -++ } -++ return (dims - index) << 28 | data; -++ } -++ } -++ -++ /** -++ * Pops a type from the output frame stack and returns its value. -++ * -++ * @return the type that has been popped from the output frame stack. -++ */ -++ private int pop() { -++ if (outputStackTop > 0) { -++ return outputStack[--outputStackTop]; -++ } else { -++ // if the output frame stack is empty, pops from the input stack -++ return STACK | -(--owner.inputStackTop); -++ } -++ } -++ -++ /** -++ * Pops the given number of types from the output frame stack. -++ * -++ * @param elements -++ * the number of types that must be popped. -++ */ -++ private void pop(final int elements) { -++ if (outputStackTop >= elements) { -++ outputStackTop -= elements; -++ } else { -++ // if the number of elements to be popped is greater than the number -++ // of elements in the output stack, clear it, and pops the remaining -++ // elements from the input stack. -++ owner.inputStackTop -= elements - outputStackTop; -++ outputStackTop = 0; -++ } -++ } -++ -++ /** -++ * Pops a type from the output frame stack. -++ * -++ * @param desc -++ * the descriptor of the type to be popped. Can also be a method -++ * descriptor (in this case this method pops the types -++ * corresponding to the method arguments). -++ */ -++ private void pop(final String desc) { -++ char c = desc.charAt(0); -++ if (c == '(') { -++ pop((Type.getArgumentsAndReturnSizes(desc) >> 2) - 1); -++ } else if (c == 'J' || c == 'D') { -++ pop(2); -++ } else { -++ pop(1); -++ } -++ } -++ -++ /** -++ * Adds a new type to the list of types on which a constructor is invoked in -++ * the basic block. -++ * -++ * @param var -++ * a type on a which a constructor is invoked. -++ */ -++ private void init(final int var) { -++ // creates and/or resizes the initializations array if necessary -++ if (initializations == null) { -++ initializations = new int[2]; -++ } -++ int n = initializations.length; -++ if (initializationCount >= n) { -++ int[] t = new int[Math.max(initializationCount + 1, 2 * n)]; -++ System.arraycopy(initializations, 0, t, 0, n); -++ initializations = t; -++ } -++ // stores the type to be initialized -++ initializations[initializationCount++] = var; -++ } -++ -++ /** -++ * Replaces the given type with the appropriate type if it is one of the -++ * types on which a constructor is invoked in the basic block. -++ * -++ * @param cw -++ * the ClassWriter to which this label belongs. -++ * @param t -++ * a type -++ * @return t or, if t is one of the types on which a constructor is invoked -++ * in the basic block, the type corresponding to this constructor. -++ */ -++ private int init(final ClassWriter cw, final int t) { -++ int s; -++ if (t == UNINITIALIZED_THIS) { -++ s = OBJECT | cw.addType(cw.thisName); -++ } else if ((t & (DIM | BASE_KIND)) == UNINITIALIZED) { -++ String type = cw.typeTable[t & BASE_VALUE].strVal1; -++ s = OBJECT | cw.addType(type); -++ } else { -++ return t; -++ } -++ for (int j = 0; j < initializationCount; ++j) { -++ int u = initializations[j]; -++ int dim = u & DIM; -++ int kind = u & KIND; -++ if (kind == LOCAL) { -++ u = dim + inputLocals[u & VALUE]; -++ } else if (kind == STACK) { -++ u = dim + inputStack[inputStack.length - (u & VALUE)]; -++ } -++ if (t == u) { -++ return s; -++ } -++ } -++ return t; -++ } -++ -++ /** -++ * Initializes the input frame of the first basic block from the method -++ * descriptor. -++ * -++ * @param cw -++ * the ClassWriter to which this label belongs. -++ * @param access -++ * the access flags of the method to which this label belongs. -++ * @param args -++ * the formal parameter types of this method. -++ * @param maxLocals -++ * the maximum number of local variables of this method. -++ */ -++ void initInputFrame(final ClassWriter cw, final int access, -++ final Type[] args, final int maxLocals) { -++ inputLocals = new int[maxLocals]; -++ inputStack = new int[0]; -++ int i = 0; -++ if ((access & Opcodes.ACC_STATIC) == 0) { -++ if ((access & MethodWriter.ACC_CONSTRUCTOR) == 0) { -++ inputLocals[i++] = OBJECT | cw.addType(cw.thisName); -++ } else { -++ inputLocals[i++] = UNINITIALIZED_THIS; -++ } -++ } -++ for (int j = 0; j < args.length; ++j) { -++ int t = type(cw, args[j].getDescriptor()); -++ inputLocals[i++] = t; -++ if (t == LONG || t == DOUBLE) { -++ inputLocals[i++] = TOP; -++ } -++ } -++ while (i < maxLocals) { -++ inputLocals[i++] = TOP; -++ } -++ } -++ -++ /** -++ * Simulates the action of the given instruction on the output stack frame. -++ * -++ * @param opcode -++ * the opcode of the instruction. -++ * @param arg -++ * the operand of the instruction, if any. -++ * @param cw -++ * the class writer to which this label belongs. -++ * @param item -++ * the operand of the instructions, if any. -++ */ -++ void execute(final int opcode, final int arg, final ClassWriter cw, -++ final Item item) { -++ int t1, t2, t3, t4; -++ switch (opcode) { -++ case Opcodes.NOP: -++ case Opcodes.INEG: -++ case Opcodes.LNEG: -++ case Opcodes.FNEG: -++ case Opcodes.DNEG: -++ case Opcodes.I2B: -++ case Opcodes.I2C: -++ case Opcodes.I2S: -++ case Opcodes.GOTO: -++ case Opcodes.RETURN: -++ break; -++ case Opcodes.ACONST_NULL: -++ push(NULL); -++ break; -++ case Opcodes.ICONST_M1: -++ case Opcodes.ICONST_0: -++ case Opcodes.ICONST_1: -++ case Opcodes.ICONST_2: -++ case Opcodes.ICONST_3: -++ case Opcodes.ICONST_4: -++ case Opcodes.ICONST_5: -++ case Opcodes.BIPUSH: -++ case Opcodes.SIPUSH: -++ case Opcodes.ILOAD: -++ push(INTEGER); -++ break; -++ case Opcodes.LCONST_0: -++ case Opcodes.LCONST_1: -++ case Opcodes.LLOAD: -++ push(LONG); -++ push(TOP); -++ break; -++ case Opcodes.FCONST_0: -++ case Opcodes.FCONST_1: -++ case Opcodes.FCONST_2: -++ case Opcodes.FLOAD: -++ push(FLOAT); -++ break; -++ case Opcodes.DCONST_0: -++ case Opcodes.DCONST_1: -++ case Opcodes.DLOAD: -++ push(DOUBLE); -++ push(TOP); -++ break; -++ case Opcodes.LDC: -++ switch (item.type) { -++ case ClassWriter.INT: -++ push(INTEGER); -++ break; -++ case ClassWriter.LONG: -++ push(LONG); -++ push(TOP); -++ break; -++ case ClassWriter.FLOAT: -++ push(FLOAT); -++ break; -++ case ClassWriter.DOUBLE: -++ push(DOUBLE); -++ push(TOP); -++ break; -++ case ClassWriter.CLASS: -++ push(OBJECT | cw.addType("java/lang/Class")); -++ break; -++ case ClassWriter.STR: -++ push(OBJECT | cw.addType("java/lang/String")); -++ break; -++ case ClassWriter.MTYPE: -++ push(OBJECT | cw.addType("java/lang/invoke/MethodType")); -++ break; -++ // case ClassWriter.HANDLE_BASE + [1..9]: -++ default: -++ push(OBJECT | cw.addType("java/lang/invoke/MethodHandle")); -++ } -++ break; -++ case Opcodes.ALOAD: -++ push(get(arg)); -++ break; -++ case Opcodes.IALOAD: -++ case Opcodes.BALOAD: -++ case Opcodes.CALOAD: -++ case Opcodes.SALOAD: -++ pop(2); -++ push(INTEGER); -++ break; -++ case Opcodes.LALOAD: -++ case Opcodes.D2L: -++ pop(2); -++ push(LONG); -++ push(TOP); -++ break; -++ case Opcodes.FALOAD: -++ pop(2); -++ push(FLOAT); -++ break; -++ case Opcodes.DALOAD: -++ case Opcodes.L2D: -++ pop(2); -++ push(DOUBLE); -++ push(TOP); -++ break; -++ case Opcodes.AALOAD: -++ pop(1); -++ t1 = pop(); -++ push(ELEMENT_OF + t1); -++ break; -++ case Opcodes.ISTORE: -++ case Opcodes.FSTORE: -++ case Opcodes.ASTORE: -++ t1 = pop(); -++ set(arg, t1); -++ if (arg > 0) { -++ t2 = get(arg - 1); -++ // if t2 is of kind STACK or LOCAL we cannot know its size! -++ if (t2 == LONG || t2 == DOUBLE) { -++ set(arg - 1, TOP); -++ } else if ((t2 & KIND) != BASE) { -++ set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE); -++ } -++ } -++ break; -++ case Opcodes.LSTORE: -++ case Opcodes.DSTORE: -++ pop(1); -++ t1 = pop(); -++ set(arg, t1); -++ set(arg + 1, TOP); -++ if (arg > 0) { -++ t2 = get(arg - 1); -++ // if t2 is of kind STACK or LOCAL we cannot know its size! -++ if (t2 == LONG || t2 == DOUBLE) { -++ set(arg - 1, TOP); -++ } else if ((t2 & KIND) != BASE) { -++ set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE); -++ } -++ } -++ break; -++ case Opcodes.IASTORE: -++ case Opcodes.BASTORE: -++ case Opcodes.CASTORE: -++ case Opcodes.SASTORE: -++ case Opcodes.FASTORE: -++ case Opcodes.AASTORE: -++ pop(3); -++ break; -++ case Opcodes.LASTORE: -++ case Opcodes.DASTORE: -++ pop(4); -++ break; -++ case Opcodes.POP: -++ case Opcodes.IFEQ: -++ case Opcodes.IFNE: -++ case Opcodes.IFLT: -++ case Opcodes.IFGE: -++ case Opcodes.IFGT: -++ case Opcodes.IFLE: -++ case Opcodes.IRETURN: -++ case Opcodes.FRETURN: -++ case Opcodes.ARETURN: -++ case Opcodes.TABLESWITCH: -++ case Opcodes.LOOKUPSWITCH: -++ case Opcodes.ATHROW: -++ case Opcodes.MONITORENTER: -++ case Opcodes.MONITOREXIT: -++ case Opcodes.IFNULL: -++ case Opcodes.IFNONNULL: -++ pop(1); -++ break; -++ case Opcodes.POP2: -++ case Opcodes.IF_ICMPEQ: -++ case Opcodes.IF_ICMPNE: -++ case Opcodes.IF_ICMPLT: -++ case Opcodes.IF_ICMPGE: -++ case Opcodes.IF_ICMPGT: -++ case Opcodes.IF_ICMPLE: -++ case Opcodes.IF_ACMPEQ: -++ case Opcodes.IF_ACMPNE: -++ case Opcodes.LRETURN: -++ case Opcodes.DRETURN: -++ pop(2); -++ break; -++ case Opcodes.DUP: -++ t1 = pop(); -++ push(t1); -++ push(t1); -++ break; -++ case Opcodes.DUP_X1: -++ t1 = pop(); -++ t2 = pop(); -++ push(t1); -++ push(t2); -++ push(t1); -++ break; -++ case Opcodes.DUP_X2: -++ t1 = pop(); -++ t2 = pop(); -++ t3 = pop(); -++ push(t1); -++ push(t3); -++ push(t2); -++ push(t1); -++ break; -++ case Opcodes.DUP2: -++ t1 = pop(); -++ t2 = pop(); -++ push(t2); -++ push(t1); -++ push(t2); -++ push(t1); -++ break; -++ case Opcodes.DUP2_X1: -++ t1 = pop(); -++ t2 = pop(); -++ t3 = pop(); -++ push(t2); -++ push(t1); -++ push(t3); -++ push(t2); -++ push(t1); -++ break; -++ case Opcodes.DUP2_X2: -++ t1 = pop(); -++ t2 = pop(); -++ t3 = pop(); -++ t4 = pop(); -++ push(t2); -++ push(t1); -++ push(t4); -++ push(t3); -++ push(t2); -++ push(t1); -++ break; -++ case Opcodes.SWAP: -++ t1 = pop(); -++ t2 = pop(); -++ push(t1); -++ push(t2); -++ break; -++ case Opcodes.IADD: -++ case Opcodes.ISUB: -++ case Opcodes.IMUL: -++ case Opcodes.IDIV: -++ case Opcodes.IREM: -++ case Opcodes.IAND: -++ case Opcodes.IOR: -++ case Opcodes.IXOR: -++ case Opcodes.ISHL: -++ case Opcodes.ISHR: -++ case Opcodes.IUSHR: -++ case Opcodes.L2I: -++ case Opcodes.D2I: -++ case Opcodes.FCMPL: -++ case Opcodes.FCMPG: -++ pop(2); -++ push(INTEGER); -++ break; -++ case Opcodes.LADD: -++ case Opcodes.LSUB: -++ case Opcodes.LMUL: -++ case Opcodes.LDIV: -++ case Opcodes.LREM: -++ case Opcodes.LAND: -++ case Opcodes.LOR: -++ case Opcodes.LXOR: -++ pop(4); -++ push(LONG); -++ push(TOP); -++ break; -++ case Opcodes.FADD: -++ case Opcodes.FSUB: -++ case Opcodes.FMUL: -++ case Opcodes.FDIV: -++ case Opcodes.FREM: -++ case Opcodes.L2F: -++ case Opcodes.D2F: -++ pop(2); -++ push(FLOAT); -++ break; -++ case Opcodes.DADD: -++ case Opcodes.DSUB: -++ case Opcodes.DMUL: -++ case Opcodes.DDIV: -++ case Opcodes.DREM: -++ pop(4); -++ push(DOUBLE); -++ push(TOP); -++ break; -++ case Opcodes.LSHL: -++ case Opcodes.LSHR: -++ case Opcodes.LUSHR: -++ pop(3); -++ push(LONG); -++ push(TOP); -++ break; -++ case Opcodes.IINC: -++ set(arg, INTEGER); -++ break; -++ case Opcodes.I2L: -++ case Opcodes.F2L: -++ pop(1); -++ push(LONG); -++ push(TOP); -++ break; -++ case Opcodes.I2F: -++ pop(1); -++ push(FLOAT); -++ break; -++ case Opcodes.I2D: -++ case Opcodes.F2D: -++ pop(1); -++ push(DOUBLE); -++ push(TOP); -++ break; -++ case Opcodes.F2I: -++ case Opcodes.ARRAYLENGTH: -++ case Opcodes.INSTANCEOF: -++ pop(1); -++ push(INTEGER); -++ break; -++ case Opcodes.LCMP: -++ case Opcodes.DCMPL: -++ case Opcodes.DCMPG: -++ pop(4); -++ push(INTEGER); -++ break; -++ case Opcodes.JSR: -++ case Opcodes.RET: -++ throw new RuntimeException( -++ "JSR/RET are not supported with computeFrames option"); -++ case Opcodes.GETSTATIC: -++ push(cw, item.strVal3); -++ break; -++ case Opcodes.PUTSTATIC: -++ pop(item.strVal3); -++ break; -++ case Opcodes.GETFIELD: -++ pop(1); -++ push(cw, item.strVal3); -++ break; -++ case Opcodes.PUTFIELD: -++ pop(item.strVal3); -++ pop(); -++ break; -++ case Opcodes.INVOKEVIRTUAL: -++ case Opcodes.INVOKESPECIAL: -++ case Opcodes.INVOKESTATIC: -++ case Opcodes.INVOKEINTERFACE: -++ pop(item.strVal3); -++ if (opcode != Opcodes.INVOKESTATIC) { -++ t1 = pop(); -++ if (opcode == Opcodes.INVOKESPECIAL -++ && item.strVal2.charAt(0) == '<') { -++ init(t1); -++ } -++ } -++ push(cw, item.strVal3); -++ break; -++ case Opcodes.INVOKEDYNAMIC: -++ pop(item.strVal2); -++ push(cw, item.strVal2); -++ break; -++ case Opcodes.NEW: -++ push(UNINITIALIZED | cw.addUninitializedType(item.strVal1, arg)); -++ break; -++ case Opcodes.NEWARRAY: -++ pop(); -++ switch (arg) { -++ case Opcodes.T_BOOLEAN: -++ push(ARRAY_OF | BOOLEAN); -++ break; -++ case Opcodes.T_CHAR: -++ push(ARRAY_OF | CHAR); -++ break; -++ case Opcodes.T_BYTE: -++ push(ARRAY_OF | BYTE); -++ break; -++ case Opcodes.T_SHORT: -++ push(ARRAY_OF | SHORT); -++ break; -++ case Opcodes.T_INT: -++ push(ARRAY_OF | INTEGER); -++ break; -++ case Opcodes.T_FLOAT: -++ push(ARRAY_OF | FLOAT); -++ break; -++ case Opcodes.T_DOUBLE: -++ push(ARRAY_OF | DOUBLE); -++ break; -++ // case Opcodes.T_LONG: -++ default: -++ push(ARRAY_OF | LONG); -++ break; -++ } -++ break; -++ case Opcodes.ANEWARRAY: -++ String s = item.strVal1; -++ pop(); -++ if (s.charAt(0) == '[') { -++ push(cw, '[' + s); -++ } else { -++ push(ARRAY_OF | OBJECT | cw.addType(s)); -++ } -++ break; -++ case Opcodes.CHECKCAST: -++ s = item.strVal1; -++ pop(); -++ if (s.charAt(0) == '[') { -++ push(cw, s); -++ } else { -++ push(OBJECT | cw.addType(s)); -++ } -++ break; -++ // case Opcodes.MULTIANEWARRAY: -++ default: -++ pop(arg); -++ push(cw, item.strVal1); -++ break; -++ } -++ } -++ -++ /** -++ * Merges the input frame of the given basic block with the input and output -++ * frames of this basic block. Returns true if the input frame of -++ * the given label has been changed by this operation. -++ * -++ * @param cw -++ * the ClassWriter to which this label belongs. -++ * @param frame -++ * the basic block whose input frame must be updated. -++ * @param edge -++ * the kind of the {@link Edge} between this label and 'label'. -++ * See {@link Edge#info}. -++ * @return true if the input frame of the given label has been -++ * changed by this operation. -++ */ -++ boolean merge(final ClassWriter cw, final Frame frame, final int edge) { -++ boolean changed = false; -++ int i, s, dim, kind, t; -++ -++ int nLocal = inputLocals.length; -++ int nStack = inputStack.length; -++ if (frame.inputLocals == null) { -++ frame.inputLocals = new int[nLocal]; -++ changed = true; -++ } -++ -++ for (i = 0; i < nLocal; ++i) { -++ if (outputLocals != null && i < outputLocals.length) { -++ s = outputLocals[i]; -++ if (s == 0) { -++ t = inputLocals[i]; -++ } else { -++ dim = s & DIM; -++ kind = s & KIND; -++ if (kind == BASE) { -++ t = s; -++ } else { -++ if (kind == LOCAL) { -++ t = dim + inputLocals[s & VALUE]; -++ } else { -++ t = dim + inputStack[nStack - (s & VALUE)]; -++ } -++ if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 -++ && (t == LONG || t == DOUBLE)) { -++ t = TOP; -++ } -++ } -++ } -++ } else { -++ t = inputLocals[i]; -++ } -++ if (initializations != null) { -++ t = init(cw, t); -++ } -++ changed |= merge(cw, t, frame.inputLocals, i); -++ } -++ -++ if (edge > 0) { -++ for (i = 0; i < nLocal; ++i) { -++ t = inputLocals[i]; -++ changed |= merge(cw, t, frame.inputLocals, i); -++ } -++ if (frame.inputStack == null) { -++ frame.inputStack = new int[1]; -++ changed = true; -++ } -++ changed |= merge(cw, edge, frame.inputStack, 0); -++ return changed; -++ } -++ -++ int nInputStack = inputStack.length + owner.inputStackTop; -++ if (frame.inputStack == null) { -++ frame.inputStack = new int[nInputStack + outputStackTop]; -++ changed = true; -++ } -++ -++ for (i = 0; i < nInputStack; ++i) { -++ t = inputStack[i]; -++ if (initializations != null) { -++ t = init(cw, t); -++ } -++ changed |= merge(cw, t, frame.inputStack, i); -++ } -++ for (i = 0; i < outputStackTop; ++i) { -++ s = outputStack[i]; -++ dim = s & DIM; -++ kind = s & KIND; -++ if (kind == BASE) { -++ t = s; -++ } else { -++ if (kind == LOCAL) { -++ t = dim + inputLocals[s & VALUE]; -++ } else { -++ t = dim + inputStack[nStack - (s & VALUE)]; -++ } -++ if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 -++ && (t == LONG || t == DOUBLE)) { -++ t = TOP; -++ } -++ } -++ if (initializations != null) { -++ t = init(cw, t); -++ } -++ changed |= merge(cw, t, frame.inputStack, nInputStack + i); -++ } -++ return changed; -++ } -++ -++ /** -++ * Merges the type at the given index in the given type array with the given -++ * type. Returns true if the type array has been modified by this -++ * operation. -++ * -++ * @param cw -++ * the ClassWriter to which this label belongs. -++ * @param t -++ * the type with which the type array element must be merged. -++ * @param types -++ * an array of types. -++ * @param index -++ * the index of the type that must be merged in 'types'. -++ * @return true if the type array has been modified by this -++ * operation. -++ */ -++ private static boolean merge(final ClassWriter cw, int t, -++ final int[] types, final int index) { -++ int u = types[index]; -++ if (u == t) { -++ // if the types are equal, merge(u,t)=u, so there is no change -++ return false; -++ } -++ if ((t & ~DIM) == NULL) { -++ if (u == NULL) { -++ return false; -++ } -++ t = NULL; -++ } -++ if (u == 0) { -++ // if types[index] has never been assigned, merge(u,t)=t -++ types[index] = t; -++ return true; -++ } -++ int v; -++ if ((u & BASE_KIND) == OBJECT || (u & DIM) != 0) { -++ // if u is a reference type of any dimension -++ if (t == NULL) { -++ // if t is the NULL type, merge(u,t)=u, so there is no change -++ return false; -++ } else if ((t & (DIM | BASE_KIND)) == (u & (DIM | BASE_KIND))) { -++ // if t and u have the same dimension and same base kind -++ if ((u & BASE_KIND) == OBJECT) { -++ // if t is also a reference type, and if u and t have the -++ // same dimension merge(u,t) = dim(t) | common parent of the -++ // element types of u and t -++ v = (t & DIM) | OBJECT -++ | cw.getMergedType(t & BASE_VALUE, u & BASE_VALUE); -++ } else { -++ // if u and t are array types, but not with the same element -++ // type, merge(u,t) = dim(u) - 1 | java/lang/Object -++ int vdim = ELEMENT_OF + (u & DIM); -++ v = vdim | OBJECT | cw.addType("java/lang/Object"); -++ } -++ } else if ((t & BASE_KIND) == OBJECT || (t & DIM) != 0) { -++ // if t is any other reference or array type, the merged type -++ // is min(udim, tdim) | java/lang/Object, where udim is the -++ // array dimension of u, minus 1 if u is an array type with a -++ // primitive element type (and similarly for tdim). -++ int tdim = (((t & DIM) == 0 || (t & BASE_KIND) == OBJECT) ? 0 -++ : ELEMENT_OF) + (t & DIM); -++ int udim = (((u & DIM) == 0 || (u & BASE_KIND) == OBJECT) ? 0 -++ : ELEMENT_OF) + (u & DIM); -++ v = Math.min(tdim, udim) | OBJECT -++ | cw.addType("java/lang/Object"); -++ } else { -++ // if t is any other type, merge(u,t)=TOP -++ v = TOP; -++ } -++ } else if (u == NULL) { -++ // if u is the NULL type, merge(u,t)=t, -++ // or TOP if t is not a reference type -++ v = (t & BASE_KIND) == OBJECT || (t & DIM) != 0 ? t : TOP; -++ } else { -++ // if u is any other type, merge(u,t)=TOP whatever t -++ v = TOP; -++ } -++ if (u != v) { -++ types[index] = v; -++ return true; -++ } -++ return false; -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/Handle.java b/contrib/asm/src/org/objectweb/asm/Handle.java -+new file mode 100644 -+index 0000000..a627911 -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/Handle.java -+@@ -0,0 +1,170 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++ -++package org.objectweb.asm; -++ -++/** -++ * A reference to a field or a method. -++ * -++ * @author Remi Forax -++ * @author Eric Bruneton -++ */ -++public final class Handle { -++ -++ /** -++ * The kind of field or method designated by this Handle. Should be -++ * {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, -++ * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, -++ * {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, -++ * {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or -++ * {@link Opcodes#H_INVOKEINTERFACE}. -++ */ -++ final int tag; -++ -++ /** -++ * The internal name of the class that owns the field or method designated -++ * by this handle. -++ */ -++ final String owner; -++ -++ /** -++ * The name of the field or method designated by this handle. -++ */ -++ final String name; -++ -++ /** -++ * The descriptor of the field or method designated by this handle. -++ */ -++ final String desc; -++ -++ /** -++ * Constructs a new field or method handle. -++ * -++ * @param tag -++ * the kind of field or method designated by this Handle. Must be -++ * {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, -++ * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, -++ * {@link Opcodes#H_INVOKEVIRTUAL}, -++ * {@link Opcodes#H_INVOKESTATIC}, -++ * {@link Opcodes#H_INVOKESPECIAL}, -++ * {@link Opcodes#H_NEWINVOKESPECIAL} or -++ * {@link Opcodes#H_INVOKEINTERFACE}. -++ * @param owner -++ * the internal name of the class that owns the field or method -++ * designated by this handle. -++ * @param name -++ * the name of the field or method designated by this handle. -++ * @param desc -++ * the descriptor of the field or method designated by this -++ * handle. -++ */ -++ public Handle(int tag, String owner, String name, String desc) { -++ this.tag = tag; -++ this.owner = owner; -++ this.name = name; -++ this.desc = desc; -++ } -++ -++ /** -++ * Returns the kind of field or method designated by this handle. -++ * -++ * @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, -++ * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, -++ * {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, -++ * {@link Opcodes#H_INVOKESPECIAL}, -++ * {@link Opcodes#H_NEWINVOKESPECIAL} or -++ * {@link Opcodes#H_INVOKEINTERFACE}. -++ */ -++ public int getTag() { -++ return tag; -++ } -++ -++ /** -++ * Returns the internal name of the class that owns the field or method -++ * designated by this handle. -++ * -++ * @return the internal name of the class that owns the field or method -++ * designated by this handle. -++ */ -++ public String getOwner() { -++ return owner; -++ } -++ -++ /** -++ * Returns the name of the field or method designated by this handle. -++ * -++ * @return the name of the field or method designated by this handle. -++ */ -++ public String getName() { -++ return name; -++ } -++ -++ /** -++ * Returns the descriptor of the field or method designated by this handle. -++ * -++ * @return the descriptor of the field or method designated by this handle. -++ */ -++ public String getDesc() { -++ return desc; -++ } -++ -++ @Override -++ public boolean equals(Object obj) { -++ if (obj == this) { -++ return true; -++ } -++ if (!(obj instanceof Handle)) { -++ return false; -++ } -++ Handle h = (Handle) obj; -++ return tag == h.tag && owner.equals(h.owner) && name.equals(h.name) -++ && desc.equals(h.desc); -++ } -++ -++ @Override -++ public int hashCode() { -++ return tag + owner.hashCode() * name.hashCode() * desc.hashCode(); -++ } -++ -++ /** -++ * Returns the textual representation of this handle. The textual -++ * representation is: -++ * -++ *
-++     * owner '.' name desc ' ' '(' tag ')'
-++     * 
-++ * -++ * . As this format is unambiguous, it can be parsed if necessary. -++ */ -++ @Override -++ public String toString() { -++ return owner + '.' + name + desc + " (" + tag + ')'; -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/Handler.java b/contrib/asm/src/org/objectweb/asm/Handler.java -+new file mode 100644 -+index 0000000..b24591d -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/Handler.java -+@@ -0,0 +1,121 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * Information about an exception handler block. -++ * -++ * @author Eric Bruneton -++ */ -++class Handler { -++ -++ /** -++ * Beginning of the exception handler's scope (inclusive). -++ */ -++ Label start; -++ -++ /** -++ * End of the exception handler's scope (exclusive). -++ */ -++ Label end; -++ -++ /** -++ * Beginning of the exception handler's code. -++ */ -++ Label handler; -++ -++ /** -++ * Internal name of the type of exceptions handled by this handler, or -++ * null to catch any exceptions. -++ */ -++ String desc; -++ -++ /** -++ * Constant pool index of the internal name of the type of exceptions -++ * handled by this handler, or 0 to catch any exceptions. -++ */ -++ int type; -++ -++ /** -++ * Next exception handler block info. -++ */ -++ Handler next; -++ -++ /** -++ * Removes the range between start and end from the given exception -++ * handlers. -++ * -++ * @param h -++ * an exception handler list. -++ * @param start -++ * the start of the range to be removed. -++ * @param end -++ * the end of the range to be removed. Maybe null. -++ * @return the exception handler list with the start-end range removed. -++ */ -++ static Handler remove(Handler h, Label start, Label end) { -++ if (h == null) { -++ return null; -++ } else { -++ h.next = remove(h.next, start, end); -++ } -++ int hstart = h.start.position; -++ int hend = h.end.position; -++ int s = start.position; -++ int e = end == null ? Integer.MAX_VALUE : end.position; -++ // if [hstart,hend[ and [s,e[ intervals intersect... -++ if (s < hend && e > hstart) { -++ if (s <= hstart) { -++ if (e >= hend) { -++ // [hstart,hend[ fully included in [s,e[, h removed -++ h = h.next; -++ } else { -++ // [hstart,hend[ minus [s,e[ = [e,hend[ -++ h.start = end; -++ } -++ } else if (e >= hend) { -++ // [hstart,hend[ minus [s,e[ = [hstart,s[ -++ h.end = start; -++ } else { -++ // [hstart,hend[ minus [s,e[ = [hstart,s[ + [e,hend[ -++ Handler g = new Handler(); -++ g.start = end; -++ g.end = h.end; -++ g.handler = h.handler; -++ g.desc = h.desc; -++ g.type = h.type; -++ g.next = h.next; -++ h.end = start; -++ h.next = g; -++ } -++ } -++ return h; -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/Item.java b/contrib/asm/src/org/objectweb/asm/Item.java -+new file mode 100644 -+index 0000000..917524d -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/Item.java -+@@ -0,0 +1,313 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * A constant pool item. Constant pool items can be created with the 'newXXX' -++ * methods in the {@link ClassWriter} class. -++ * -++ * @author Eric Bruneton -++ */ -++final class Item { -++ -++ /** -++ * Index of this item in the constant pool. -++ */ -++ int index; -++ -++ /** -++ * Type of this constant pool item. A single class is used to represent all -++ * constant pool item types, in order to minimize the bytecode size of this -++ * package. The value of this field is one of {@link ClassWriter#INT}, -++ * {@link ClassWriter#LONG}, {@link ClassWriter#FLOAT}, -++ * {@link ClassWriter#DOUBLE}, {@link ClassWriter#UTF8}, -++ * {@link ClassWriter#STR}, {@link ClassWriter#CLASS}, -++ * {@link ClassWriter#NAME_TYPE}, {@link ClassWriter#FIELD}, -++ * {@link ClassWriter#METH}, {@link ClassWriter#IMETH}, -++ * {@link ClassWriter#MTYPE}, {@link ClassWriter#INDY}. -++ * -++ * MethodHandle constant 9 variations are stored using a range of 9 values -++ * from {@link ClassWriter#HANDLE_BASE} + 1 to -++ * {@link ClassWriter#HANDLE_BASE} + 9. -++ * -++ * Special Item types are used for Items that are stored in the ClassWriter -++ * {@link ClassWriter#typeTable}, instead of the constant pool, in order to -++ * avoid clashes with normal constant pool items in the ClassWriter constant -++ * pool's hash table. These special item types are -++ * {@link ClassWriter#TYPE_NORMAL}, {@link ClassWriter#TYPE_UNINIT} and -++ * {@link ClassWriter#TYPE_MERGED}. -++ */ -++ int type; -++ -++ /** -++ * Value of this item, for an integer item. -++ */ -++ int intVal; -++ -++ /** -++ * Value of this item, for a long item. -++ */ -++ long longVal; -++ -++ /** -++ * First part of the value of this item, for items that do not hold a -++ * primitive value. -++ */ -++ String strVal1; -++ -++ /** -++ * Second part of the value of this item, for items that do not hold a -++ * primitive value. -++ */ -++ String strVal2; -++ -++ /** -++ * Third part of the value of this item, for items that do not hold a -++ * primitive value. -++ */ -++ String strVal3; -++ -++ /** -++ * The hash code value of this constant pool item. -++ */ -++ int hashCode; -++ -++ /** -++ * Link to another constant pool item, used for collision lists in the -++ * constant pool's hash table. -++ */ -++ Item next; -++ -++ /** -++ * Constructs an uninitialized {@link Item}. -++ */ -++ Item() { -++ } -++ -++ /** -++ * Constructs an uninitialized {@link Item} for constant pool element at -++ * given position. -++ * -++ * @param index -++ * index of the item to be constructed. -++ */ -++ Item(final int index) { -++ this.index = index; -++ } -++ -++ /** -++ * Constructs a copy of the given item. -++ * -++ * @param index -++ * index of the item to be constructed. -++ * @param i -++ * the item that must be copied into the item to be constructed. -++ */ -++ Item(final int index, final Item i) { -++ this.index = index; -++ type = i.type; -++ intVal = i.intVal; -++ longVal = i.longVal; -++ strVal1 = i.strVal1; -++ strVal2 = i.strVal2; -++ strVal3 = i.strVal3; -++ hashCode = i.hashCode; -++ } -++ -++ /** -++ * Sets this item to an integer item. -++ * -++ * @param intVal -++ * the value of this item. -++ */ -++ void set(final int intVal) { -++ this.type = ClassWriter.INT; -++ this.intVal = intVal; -++ this.hashCode = 0x7FFFFFFF & (type + intVal); -++ } -++ -++ /** -++ * Sets this item to a long item. -++ * -++ * @param longVal -++ * the value of this item. -++ */ -++ void set(final long longVal) { -++ this.type = ClassWriter.LONG; -++ this.longVal = longVal; -++ this.hashCode = 0x7FFFFFFF & (type + (int) longVal); -++ } -++ -++ /** -++ * Sets this item to a float item. -++ * -++ * @param floatVal -++ * the value of this item. -++ */ -++ void set(final float floatVal) { -++ this.type = ClassWriter.FLOAT; -++ this.intVal = Float.floatToRawIntBits(floatVal); -++ this.hashCode = 0x7FFFFFFF & (type + (int) floatVal); -++ } -++ -++ /** -++ * Sets this item to a double item. -++ * -++ * @param doubleVal -++ * the value of this item. -++ */ -++ void set(final double doubleVal) { -++ this.type = ClassWriter.DOUBLE; -++ this.longVal = Double.doubleToRawLongBits(doubleVal); -++ this.hashCode = 0x7FFFFFFF & (type + (int) doubleVal); -++ } -++ -++ /** -++ * Sets this item to an item that do not hold a primitive value. -++ * -++ * @param type -++ * the type of this item. -++ * @param strVal1 -++ * first part of the value of this item. -++ * @param strVal2 -++ * second part of the value of this item. -++ * @param strVal3 -++ * third part of the value of this item. -++ */ -++ @SuppressWarnings("fallthrough") -++ void set(final int type, final String strVal1, final String strVal2, -++ final String strVal3) { -++ this.type = type; -++ this.strVal1 = strVal1; -++ this.strVal2 = strVal2; -++ this.strVal3 = strVal3; -++ switch (type) { -++ case ClassWriter.CLASS: -++ this.intVal = 0; // intVal of a class must be zero, see visitInnerClass -++ case ClassWriter.UTF8: -++ case ClassWriter.STR: -++ case ClassWriter.MTYPE: -++ case ClassWriter.TYPE_NORMAL: -++ hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()); -++ return; -++ case ClassWriter.NAME_TYPE: { -++ hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() -++ * strVal2.hashCode()); -++ return; -++ } -++ // ClassWriter.FIELD: -++ // ClassWriter.METH: -++ // ClassWriter.IMETH: -++ // ClassWriter.HANDLE_BASE + 1..9 -++ default: -++ hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() -++ * strVal2.hashCode() * strVal3.hashCode()); -++ } -++ } -++ -++ /** -++ * Sets the item to an InvokeDynamic item. -++ * -++ * @param name -++ * invokedynamic's name. -++ * @param desc -++ * invokedynamic's desc. -++ * @param bsmIndex -++ * zero based index into the class attribute BootrapMethods. -++ */ -++ void set(String name, String desc, int bsmIndex) { -++ this.type = ClassWriter.INDY; -++ this.longVal = bsmIndex; -++ this.strVal1 = name; -++ this.strVal2 = desc; -++ this.hashCode = 0x7FFFFFFF & (ClassWriter.INDY + bsmIndex -++ * strVal1.hashCode() * strVal2.hashCode()); -++ } -++ -++ /** -++ * Sets the item to a BootstrapMethod item. -++ * -++ * @param position -++ * position in byte in the class attribute BootrapMethods. -++ * @param hashCode -++ * hashcode of the item. This hashcode is processed from the -++ * hashcode of the bootstrap method and the hashcode of all -++ * bootstrap arguments. -++ */ -++ void set(int position, int hashCode) { -++ this.type = ClassWriter.BSM; -++ this.intVal = position; -++ this.hashCode = hashCode; -++ } -++ -++ /** -++ * Indicates if the given item is equal to this one. This method assumes -++ * that the two items have the same {@link #type}. -++ * -++ * @param i -++ * the item to be compared to this one. Both items must have the -++ * same {@link #type}. -++ * @return true if the given item if equal to this one, -++ * false otherwise. -++ */ -++ boolean isEqualTo(final Item i) { -++ switch (type) { -++ case ClassWriter.UTF8: -++ case ClassWriter.STR: -++ case ClassWriter.CLASS: -++ case ClassWriter.MTYPE: -++ case ClassWriter.TYPE_NORMAL: -++ return i.strVal1.equals(strVal1); -++ case ClassWriter.TYPE_MERGED: -++ case ClassWriter.LONG: -++ case ClassWriter.DOUBLE: -++ return i.longVal == longVal; -++ case ClassWriter.INT: -++ case ClassWriter.FLOAT: -++ return i.intVal == intVal; -++ case ClassWriter.TYPE_UNINIT: -++ return i.intVal == intVal && i.strVal1.equals(strVal1); -++ case ClassWriter.NAME_TYPE: -++ return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2); -++ case ClassWriter.INDY: { -++ return i.longVal == longVal && i.strVal1.equals(strVal1) -++ && i.strVal2.equals(strVal2); -++ } -++ // case ClassWriter.FIELD: -++ // case ClassWriter.METH: -++ // case ClassWriter.IMETH: -++ // case ClassWriter.HANDLE_BASE + 1..9 -++ default: -++ return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2) -++ && i.strVal3.equals(strVal3); -++ } -++ } -++ -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/Label.java b/contrib/asm/src/org/objectweb/asm/Label.java -+new file mode 100644 -+index 0000000..6bca6fb -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/Label.java -+@@ -0,0 +1,565 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * A label represents a position in the bytecode of a method. Labels are used -++ * for jump, goto, and switch instructions, and for try catch blocks. A label -++ * designates the instruction that is just after. Note however that there -++ * can be other elements between a label and the instruction it designates (such -++ * as other labels, stack map frames, line numbers, etc.). -++ * -++ * @author Eric Bruneton -++ */ -++public class Label { -++ -++ /** -++ * Indicates if this label is only used for debug attributes. Such a label -++ * is not the start of a basic block, the target of a jump instruction, or -++ * an exception handler. It can be safely ignored in control flow graph -++ * analysis algorithms (for optimization purposes). -++ */ -++ static final int DEBUG = 1; -++ -++ /** -++ * Indicates if the position of this label is known. -++ */ -++ static final int RESOLVED = 2; -++ -++ /** -++ * Indicates if this label has been updated, after instruction resizing. -++ */ -++ static final int RESIZED = 4; -++ -++ /** -++ * Indicates if this basic block has been pushed in the basic block stack. -++ * See {@link MethodWriter#visitMaxs visitMaxs}. -++ */ -++ static final int PUSHED = 8; -++ -++ /** -++ * Indicates if this label is the target of a jump instruction, or the start -++ * of an exception handler. -++ */ -++ static final int TARGET = 16; -++ -++ /** -++ * Indicates if a stack map frame must be stored for this label. -++ */ -++ static final int STORE = 32; -++ -++ /** -++ * Indicates if this label corresponds to a reachable basic block. -++ */ -++ static final int REACHABLE = 64; -++ -++ /** -++ * Indicates if this basic block ends with a JSR instruction. -++ */ -++ static final int JSR = 128; -++ -++ /** -++ * Indicates if this basic block ends with a RET instruction. -++ */ -++ static final int RET = 256; -++ -++ /** -++ * Indicates if this basic block is the start of a subroutine. -++ */ -++ static final int SUBROUTINE = 512; -++ -++ /** -++ * Indicates if this subroutine basic block has been visited by a -++ * visitSubroutine(null, ...) call. -++ */ -++ static final int VISITED = 1024; -++ -++ /** -++ * Indicates if this subroutine basic block has been visited by a -++ * visitSubroutine(!null, ...) call. -++ */ -++ static final int VISITED2 = 2048; -++ -++ /** -++ * Field used to associate user information to a label. Warning: this field -++ * is used by the ASM tree package. In order to use it with the ASM tree -++ * package you must override the -++ * {@link org.objectweb.asm.tree.MethodNode#getLabelNode} method. -++ */ -++ public Object info; -++ -++ /** -++ * Flags that indicate the status of this label. -++ * -++ * @see #DEBUG -++ * @see #RESOLVED -++ * @see #RESIZED -++ * @see #PUSHED -++ * @see #TARGET -++ * @see #STORE -++ * @see #REACHABLE -++ * @see #JSR -++ * @see #RET -++ */ -++ int status; -++ -++ /** -++ * The line number corresponding to this label, if known. If there are -++ * several lines, each line is stored in a separate label, all linked via -++ * their next field (these links are created in ClassReader and removed just -++ * before visitLabel is called, so that this does not impact the rest of the -++ * code). -++ */ -++ int line; -++ -++ /** -++ * The position of this label in the code, if known. -++ */ -++ int position; -++ -++ /** -++ * Number of forward references to this label, times two. -++ */ -++ private int referenceCount; -++ -++ /** -++ * Informations about forward references. Each forward reference is -++ * described by two consecutive integers in this array: the first one is the -++ * position of the first byte of the bytecode instruction that contains the -++ * forward reference, while the second is the position of the first byte of -++ * the forward reference itself. In fact the sign of the first integer -++ * indicates if this reference uses 2 or 4 bytes, and its absolute value -++ * gives the position of the bytecode instruction. This array is also used -++ * as a bitset to store the subroutines to which a basic block belongs. This -++ * information is needed in {@linked MethodWriter#visitMaxs}, after all -++ * forward references have been resolved. Hence the same array can be used -++ * for both purposes without problems. -++ */ -++ private int[] srcAndRefPositions; -++ -++ // ------------------------------------------------------------------------ -++ -++ /* -++ * Fields for the control flow and data flow graph analysis algorithms (used -++ * to compute the maximum stack size or the stack map frames). A control -++ * flow graph contains one node per "basic block", and one edge per "jump" -++ * from one basic block to another. Each node (i.e., each basic block) is -++ * represented by the Label object that corresponds to the first instruction -++ * of this basic block. Each node also stores the list of its successors in -++ * the graph, as a linked list of Edge objects. -++ * -++ * The control flow analysis algorithms used to compute the maximum stack -++ * size or the stack map frames are similar and use two steps. The first -++ * step, during the visit of each instruction, builds information about the -++ * state of the local variables and the operand stack at the end of each -++ * basic block, called the "output frame", relatively to the frame -++ * state at the beginning of the basic block, which is called the "input -++ * frame", and which is unknown during this step. The second step, in -++ * {@link MethodWriter#visitMaxs}, is a fix point algorithm that computes -++ * information about the input frame of each basic block, from the input -++ * state of the first basic block (known from the method signature), and by -++ * the using the previously computed relative output frames. -++ * -++ * The algorithm used to compute the maximum stack size only computes the -++ * relative output and absolute input stack heights, while the algorithm -++ * used to compute stack map frames computes relative output frames and -++ * absolute input frames. -++ */ -++ -++ /** -++ * Start of the output stack relatively to the input stack. The exact -++ * semantics of this field depends on the algorithm that is used. -++ * -++ * When only the maximum stack size is computed, this field is the number of -++ * elements in the input stack. -++ * -++ * When the stack map frames are completely computed, this field is the -++ * offset of the first output stack element relatively to the top of the -++ * input stack. This offset is always negative or null. A null offset means -++ * that the output stack must be appended to the input stack. A -n offset -++ * means that the first n output stack elements must replace the top n input -++ * stack elements, and that the other elements must be appended to the input -++ * stack. -++ */ -++ int inputStackTop; -++ -++ /** -++ * Maximum height reached by the output stack, relatively to the top of the -++ * input stack. This maximum is always positive or null. -++ */ -++ int outputStackMax; -++ -++ /** -++ * Information about the input and output stack map frames of this basic -++ * block. This field is only used when {@link ClassWriter#COMPUTE_FRAMES} -++ * option is used. -++ */ -++ Frame frame; -++ -++ /** -++ * The successor of this label, in the order they are visited. This linked -++ * list does not include labels used for debug info only. If -++ * {@link ClassWriter#COMPUTE_FRAMES} option is used then, in addition, it -++ * does not contain successive labels that denote the same bytecode position -++ * (in this case only the first label appears in this list). -++ */ -++ Label successor; -++ -++ /** -++ * The successors of this node in the control flow graph. These successors -++ * are stored in a linked list of {@link Edge Edge} objects, linked to each -++ * other by their {@link Edge#next} field. -++ */ -++ Edge successors; -++ -++ /** -++ * The next basic block in the basic block stack. This stack is used in the -++ * main loop of the fix point algorithm used in the second step of the -++ * control flow analysis algorithms. It is also used in -++ * {@link #visitSubroutine} to avoid using a recursive method, and in -++ * ClassReader to temporarily store multiple source lines for a label. -++ * -++ * @see MethodWriter#visitMaxs -++ */ -++ Label next; -++ -++ // ------------------------------------------------------------------------ -++ // Constructor -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Constructs a new label. -++ */ -++ public Label() { -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Methods to compute offsets and to manage forward references -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Returns the offset corresponding to this label. This offset is computed -++ * from the start of the method's bytecode. This method is intended for -++ * {@link Attribute} sub classes, and is normally not needed by class -++ * generators or adapters. -++ * -++ * @return the offset corresponding to this label. -++ * @throws IllegalStateException -++ * if this label is not resolved yet. -++ */ -++ public int getOffset() { -++ if ((status & RESOLVED) == 0) { -++ throw new IllegalStateException( -++ "Label offset position has not been resolved yet"); -++ } -++ return position; -++ } -++ -++ /** -++ * Puts a reference to this label in the bytecode of a method. If the -++ * position of the label is known, the offset is computed and written -++ * directly. Otherwise, a null offset is written and a new forward reference -++ * is declared for this label. -++ * -++ * @param owner -++ * the code writer that calls this method. -++ * @param out -++ * the bytecode of the method. -++ * @param source -++ * the position of first byte of the bytecode instruction that -++ * contains this label. -++ * @param wideOffset -++ * true if the reference must be stored in 4 bytes, or -++ * false if it must be stored with 2 bytes. -++ * @throws IllegalArgumentException -++ * if this label has not been created by the given code writer. -++ */ -++ void put(final MethodWriter owner, final ByteVector out, final int source, -++ final boolean wideOffset) { -++ if ((status & RESOLVED) == 0) { -++ if (wideOffset) { -++ addReference(-1 - source, out.length); -++ out.putInt(-1); -++ } else { -++ addReference(source, out.length); -++ out.putShort(-1); -++ } -++ } else { -++ if (wideOffset) { -++ out.putInt(position - source); -++ } else { -++ out.putShort(position - source); -++ } -++ } -++ } -++ -++ /** -++ * Adds a forward reference to this label. This method must be called only -++ * for a true forward reference, i.e. only if this label is not resolved -++ * yet. For backward references, the offset of the reference can be, and -++ * must be, computed and stored directly. -++ * -++ * @param sourcePosition -++ * the position of the referencing instruction. This position -++ * will be used to compute the offset of this forward reference. -++ * @param referencePosition -++ * the position where the offset for this forward reference must -++ * be stored. -++ */ -++ private void addReference(final int sourcePosition, -++ final int referencePosition) { -++ if (srcAndRefPositions == null) { -++ srcAndRefPositions = new int[6]; -++ } -++ if (referenceCount >= srcAndRefPositions.length) { -++ int[] a = new int[srcAndRefPositions.length + 6]; -++ System.arraycopy(srcAndRefPositions, 0, a, 0, -++ srcAndRefPositions.length); -++ srcAndRefPositions = a; -++ } -++ srcAndRefPositions[referenceCount++] = sourcePosition; -++ srcAndRefPositions[referenceCount++] = referencePosition; -++ } -++ -++ /** -++ * Resolves all forward references to this label. This method must be called -++ * when this label is added to the bytecode of the method, i.e. when its -++ * position becomes known. This method fills in the blanks that where left -++ * in the bytecode by each forward reference previously added to this label. -++ * -++ * @param owner -++ * the code writer that calls this method. -++ * @param position -++ * the position of this label in the bytecode. -++ * @param data -++ * the bytecode of the method. -++ * @return true if a blank that was left for this label was to -++ * small to store the offset. In such a case the corresponding jump -++ * instruction is replaced with a pseudo instruction (using unused -++ * opcodes) using an unsigned two bytes offset. These pseudo -++ * instructions will need to be replaced with true instructions with -++ * wider offsets (4 bytes instead of 2). This is done in -++ * {@link MethodWriter#resizeInstructions}. -++ * @throws IllegalArgumentException -++ * if this label has already been resolved, or if it has not -++ * been created by the given code writer. -++ */ -++ boolean resolve(final MethodWriter owner, final int position, -++ final byte[] data) { -++ boolean needUpdate = false; -++ this.status |= RESOLVED; -++ this.position = position; -++ int i = 0; -++ while (i < referenceCount) { -++ int source = srcAndRefPositions[i++]; -++ int reference = srcAndRefPositions[i++]; -++ int offset; -++ if (source >= 0) { -++ offset = position - source; -++ if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) { -++ /* -++ * changes the opcode of the jump instruction, in order to -++ * be able to find it later (see resizeInstructions in -++ * MethodWriter). These temporary opcodes are similar to -++ * jump instruction opcodes, except that the 2 bytes offset -++ * is unsigned (and can therefore represent values from 0 to -++ * 65535, which is sufficient since the size of a method is -++ * limited to 65535 bytes). -++ */ -++ int opcode = data[reference - 1] & 0xFF; -++ if (opcode <= Opcodes.JSR) { -++ // changes IFEQ ... JSR to opcodes 202 to 217 -++ data[reference - 1] = (byte) (opcode + 49); -++ } else { -++ // changes IFNULL and IFNONNULL to opcodes 218 and 219 -++ data[reference - 1] = (byte) (opcode + 20); -++ } -++ needUpdate = true; -++ } -++ data[reference++] = (byte) (offset >>> 8); -++ data[reference] = (byte) offset; -++ } else { -++ offset = position + source + 1; -++ data[reference++] = (byte) (offset >>> 24); -++ data[reference++] = (byte) (offset >>> 16); -++ data[reference++] = (byte) (offset >>> 8); -++ data[reference] = (byte) offset; -++ } -++ } -++ return needUpdate; -++ } -++ -++ /** -++ * Returns the first label of the series to which this label belongs. For an -++ * isolated label or for the first label in a series of successive labels, -++ * this method returns the label itself. For other labels it returns the -++ * first label of the series. -++ * -++ * @return the first label of the series to which this label belongs. -++ */ -++ Label getFirst() { -++ return !ClassReader.FRAMES || frame == null ? this : frame.owner; -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Methods related to subroutines -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Returns true is this basic block belongs to the given subroutine. -++ * -++ * @param id -++ * a subroutine id. -++ * @return true is this basic block belongs to the given subroutine. -++ */ -++ boolean inSubroutine(final long id) { -++ if ((status & Label.VISITED) != 0) { -++ return (srcAndRefPositions[(int) (id >>> 32)] & (int) id) != 0; -++ } -++ return false; -++ } -++ -++ /** -++ * Returns true if this basic block and the given one belong to a common -++ * subroutine. -++ * -++ * @param block -++ * another basic block. -++ * @return true if this basic block and the given one belong to a common -++ * subroutine. -++ */ -++ boolean inSameSubroutine(final Label block) { -++ if ((status & VISITED) == 0 || (block.status & VISITED) == 0) { -++ return false; -++ } -++ for (int i = 0; i < srcAndRefPositions.length; ++i) { -++ if ((srcAndRefPositions[i] & block.srcAndRefPositions[i]) != 0) { -++ return true; -++ } -++ } -++ return false; -++ } -++ -++ /** -++ * Marks this basic block as belonging to the given subroutine. -++ * -++ * @param id -++ * a subroutine id. -++ * @param nbSubroutines -++ * the total number of subroutines in the method. -++ */ -++ void addToSubroutine(final long id, final int nbSubroutines) { -++ if ((status & VISITED) == 0) { -++ status |= VISITED; -++ srcAndRefPositions = new int[nbSubroutines / 32 + 1]; -++ } -++ srcAndRefPositions[(int) (id >>> 32)] |= (int) id; -++ } -++ -++ /** -++ * Finds the basic blocks that belong to a given subroutine, and marks these -++ * blocks as belonging to this subroutine. This method follows the control -++ * flow graph to find all the blocks that are reachable from the current -++ * block WITHOUT following any JSR target. -++ * -++ * @param JSR -++ * a JSR block that jumps to this subroutine. If this JSR is not -++ * null it is added to the successor of the RET blocks found in -++ * the subroutine. -++ * @param id -++ * the id of this subroutine. -++ * @param nbSubroutines -++ * the total number of subroutines in the method. -++ */ -++ void visitSubroutine(final Label JSR, final long id, final int nbSubroutines) { -++ // user managed stack of labels, to avoid using a recursive method -++ // (recursivity can lead to stack overflow with very large methods) -++ Label stack = this; -++ while (stack != null) { -++ // removes a label l from the stack -++ Label l = stack; -++ stack = l.next; -++ l.next = null; -++ -++ if (JSR != null) { -++ if ((l.status & VISITED2) != 0) { -++ continue; -++ } -++ l.status |= VISITED2; -++ // adds JSR to the successors of l, if it is a RET block -++ if ((l.status & RET) != 0) { -++ if (!l.inSameSubroutine(JSR)) { -++ Edge e = new Edge(); -++ e.info = l.inputStackTop; -++ e.successor = JSR.successors.successor; -++ e.next = l.successors; -++ l.successors = e; -++ } -++ } -++ } else { -++ // if the l block already belongs to subroutine 'id', continue -++ if (l.inSubroutine(id)) { -++ continue; -++ } -++ // marks the l block as belonging to subroutine 'id' -++ l.addToSubroutine(id, nbSubroutines); -++ } -++ // pushes each successor of l on the stack, except JSR targets -++ Edge e = l.successors; -++ while (e != null) { -++ // if the l block is a JSR block, then 'l.successors.next' leads -++ // to the JSR target (see {@link #visitJumpInsn}) and must -++ // therefore not be followed -++ if ((l.status & Label.JSR) == 0 || e != l.successors.next) { -++ // pushes e.successor on the stack if it not already added -++ if (e.successor.next == null) { -++ e.successor.next = stack; -++ stack = e.successor; -++ } -++ } -++ e = e.next; -++ } -++ } -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Overriden Object methods -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Returns a string representation of this label. -++ * -++ * @return a string representation of this label. -++ */ -++ @Override -++ public String toString() { -++ return "L" + System.identityHashCode(this); -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/MethodVisitor.java b/contrib/asm/src/org/objectweb/asm/MethodVisitor.java -+new file mode 100644 -+index 0000000..f0927e8 -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/MethodVisitor.java -+@@ -0,0 +1,881 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * A visitor to visit a Java method. The methods of this class must be called in -++ * the following order: ( visitParameter )* [ -++ * visitAnnotationDefault ] ( visitAnnotation | -++ * visitParameterAnnotation visitTypeAnnotation | -++ * visitAttribute )* [ visitCode ( visitFrame | -++ * visitXInsn | visitLabel | -++ * visitInsnAnnotation | visitTryCatchBlock | -++ * visitTryCatchAnnotation | visitLocalVariable | -++ * visitLocalVariableAnnotation | visitLineNumber )* -++ * visitMaxs ] visitEnd. In addition, the -++ * visitXInsn and visitLabel methods must be called in -++ * the sequential order of the bytecode instructions of the visited code, -++ * visitInsnAnnotation must be called after the annotated -++ * instruction, visitTryCatchBlock must be called before the -++ * labels passed as arguments have been visited, -++ * visitTryCatchBlockAnnotation must be called after the -++ * corresponding try catch block has been visited, and the -++ * visitLocalVariable, visitLocalVariableAnnotation and -++ * visitLineNumber methods must be called after the labels -++ * passed as arguments have been visited. -++ * -++ * @author Eric Bruneton -++ */ -++public abstract class MethodVisitor { -++ -++ /** -++ * The ASM API version implemented by this visitor. The value of this field -++ * must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -++ */ -++ protected final int api; -++ -++ /** -++ * The method visitor to which this visitor must delegate method calls. May -++ * be null. -++ */ -++ protected MethodVisitor mv; -++ -++ /** -++ * Constructs a new {@link MethodVisitor}. -++ * -++ * @param api -++ * the ASM API version implemented by this visitor. Must be one -++ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -++ */ -++ public MethodVisitor(final int api) { -++ this(api, null); -++ } -++ -++ /** -++ * Constructs a new {@link MethodVisitor}. -++ * -++ * @param api -++ * the ASM API version implemented by this visitor. Must be one -++ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -++ * @param mv -++ * the method visitor to which this visitor must delegate method -++ * calls. May be null. -++ */ -++ public MethodVisitor(final int api, final MethodVisitor mv) { -++ if (api != Opcodes.ASM4 && api != Opcodes.ASM5) { -++ throw new IllegalArgumentException(); -++ } -++ this.api = api; -++ this.mv = mv; -++ } -++ -++ // ------------------------------------------------------------------------- -++ // Parameters, annotations and non standard attributes -++ // ------------------------------------------------------------------------- -++ -++ /** -++ * Visits a parameter of this method. -++ * -++ * @param name -++ * parameter name or null if none is provided. -++ * @param access -++ * the parameter's access flags, only ACC_FINAL, -++ * ACC_SYNTHETIC or/and ACC_MANDATED are -++ * allowed (see {@link Opcodes}). -++ */ -++ public void visitParameter(String name, int access) { -++ if (api < Opcodes.ASM5) { -++ throw new RuntimeException(); -++ } -++ if (mv != null) { -++ mv.visitParameter(name, access); -++ } -++ } -++ -++ /** -++ * Visits the default value of this annotation interface method. -++ * -++ * @return a visitor to the visit the actual default value of this -++ * annotation interface method, or null if this visitor is -++ * not interested in visiting this default value. The 'name' -++ * parameters passed to the methods of this annotation visitor are -++ * ignored. Moreover, exacly one visit method must be called on this -++ * annotation visitor, followed by visitEnd. -++ */ -++ public AnnotationVisitor visitAnnotationDefault() { -++ if (mv != null) { -++ return mv.visitAnnotationDefault(); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits an annotation of this method. -++ * -++ * @param desc -++ * the class descriptor of the annotation class. -++ * @param visible -++ * true if the annotation is visible at runtime. -++ * @return a visitor to visit the annotation values, or null if -++ * this visitor is not interested in visiting this annotation. -++ */ -++ public AnnotationVisitor visitAnnotation(String desc, boolean visible) { -++ if (mv != null) { -++ return mv.visitAnnotation(desc, visible); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits an annotation on a type in the method signature. -++ * -++ * @param typeRef -++ * a reference to the annotated type. The sort of this type -++ * reference must be {@link TypeReference#METHOD_TYPE_PARAMETER -++ * METHOD_TYPE_PARAMETER}, -++ * {@link TypeReference#METHOD_TYPE_PARAMETER_BOUND -++ * METHOD_TYPE_PARAMETER_BOUND}, -++ * {@link TypeReference#METHOD_RETURN METHOD_RETURN}, -++ * {@link TypeReference#METHOD_RECEIVER METHOD_RECEIVER}, -++ * {@link TypeReference#METHOD_FORMAL_PARAMETER -++ * METHOD_FORMAL_PARAMETER} or {@link TypeReference#THROWS -++ * THROWS}. See {@link TypeReference}. -++ * @param typePath -++ * the path to the annotated type argument, wildcard bound, array -++ * element type, or static inner type within 'typeRef'. May be -++ * null if the annotation targets 'typeRef' as a whole. -++ * @param desc -++ * the class descriptor of the annotation class. -++ * @param visible -++ * true if the annotation is visible at runtime. -++ * @return a visitor to visit the annotation values, or null if -++ * this visitor is not interested in visiting this annotation. -++ */ -++ public AnnotationVisitor visitTypeAnnotation(int typeRef, -++ TypePath typePath, String desc, boolean visible) { -++ if (api < Opcodes.ASM5) { -++ throw new RuntimeException(); -++ } -++ if (mv != null) { -++ return mv.visitTypeAnnotation(typeRef, typePath, desc, visible); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits an annotation of a parameter this method. -++ * -++ * @param parameter -++ * the parameter index. -++ * @param desc -++ * the class descriptor of the annotation class. -++ * @param visible -++ * true if the annotation is visible at runtime. -++ * @return a visitor to visit the annotation values, or null if -++ * this visitor is not interested in visiting this annotation. -++ */ -++ public AnnotationVisitor visitParameterAnnotation(int parameter, -++ String desc, boolean visible) { -++ if (mv != null) { -++ return mv.visitParameterAnnotation(parameter, desc, visible); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits a non standard attribute of this method. -++ * -++ * @param attr -++ * an attribute. -++ */ -++ public void visitAttribute(Attribute attr) { -++ if (mv != null) { -++ mv.visitAttribute(attr); -++ } -++ } -++ -++ /** -++ * Starts the visit of the method's code, if any (i.e. non abstract method). -++ */ -++ public void visitCode() { -++ if (mv != null) { -++ mv.visitCode(); -++ } -++ } -++ -++ /** -++ * Visits the current state of the local variables and operand stack -++ * elements. This method must(*) be called just before any -++ * instruction i that follows an unconditional branch instruction -++ * such as GOTO or THROW, that is the target of a jump instruction, or that -++ * starts an exception handler block. The visited types must describe the -++ * values of the local variables and of the operand stack elements just -++ * before i is executed.
-++ *
-++ * (*) this is mandatory only for classes whose version is greater than or -++ * equal to {@link Opcodes#V1_6 V1_6}.
-++ *
-++ * The frames of a method must be given either in expanded form, or in -++ * compressed form (all frames must use the same format, i.e. you must not -++ * mix expanded and compressed frames within a single method): -++ *
    -++ *
  • In expanded form, all frames must have the F_NEW type.
  • -++ *
  • In compressed form, frames are basically "deltas" from the state of -++ * the previous frame: -++ *
      -++ *
    • {@link Opcodes#F_SAME} representing frame with exactly the same -++ * locals as the previous frame and with the empty stack.
    • -++ *
    • {@link Opcodes#F_SAME1} representing frame with exactly the same -++ * locals as the previous frame and with single value on the stack ( -++ * nStack is 1 and stack[0] contains value for the -++ * type of the stack item).
    • -++ *
    • {@link Opcodes#F_APPEND} representing frame with current locals are -++ * the same as the locals in the previous frame, except that additional -++ * locals are defined (nLocal is 1, 2 or 3 and -++ * local elements contains values representing added types).
    • -++ *
    • {@link Opcodes#F_CHOP} representing frame with current locals are the -++ * same as the locals in the previous frame, except that the last 1-3 locals -++ * are absent and with the empty stack (nLocals is 1, 2 or 3).
    • -++ *
    • {@link Opcodes#F_FULL} representing complete frame data.
    • -++ *
    -++ *
  • -++ *
-++ *
-++ * In both cases the first frame, corresponding to the method's parameters -++ * and access flags, is implicit and must not be visited. Also, it is -++ * illegal to visit two or more frames for the same code location (i.e., at -++ * least one instruction must be visited between two calls to visitFrame). -++ * -++ * @param type -++ * the type of this stack map frame. Must be -++ * {@link Opcodes#F_NEW} for expanded frames, or -++ * {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, -++ * {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or -++ * {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for -++ * compressed frames. -++ * @param nLocal -++ * the number of local variables in the visited frame. -++ * @param local -++ * the local variable types in this frame. This array must not be -++ * modified. Primitive types are represented by -++ * {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, -++ * {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, -++ * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or -++ * {@link Opcodes#UNINITIALIZED_THIS} (long and double are -++ * represented by a single element). Reference types are -++ * represented by String objects (representing internal names), -++ * and uninitialized types by Label objects (this label -++ * designates the NEW instruction that created this uninitialized -++ * value). -++ * @param nStack -++ * the number of operand stack elements in the visited frame. -++ * @param stack -++ * the operand stack types in this frame. This array must not be -++ * modified. Its content has the same format as the "local" -++ * array. -++ * @throws IllegalStateException -++ * if a frame is visited just after another one, without any -++ * instruction between the two (unless this frame is a -++ * Opcodes#F_SAME frame, in which case it is silently ignored). -++ */ -++ public void visitFrame(int type, int nLocal, Object[] local, int nStack, -++ Object[] stack) { -++ if (mv != null) { -++ mv.visitFrame(type, nLocal, local, nStack, stack); -++ } -++ } -++ -++ // ------------------------------------------------------------------------- -++ // Normal instructions -++ // ------------------------------------------------------------------------- -++ -++ /** -++ * Visits a zero operand instruction. -++ * -++ * @param opcode -++ * the opcode of the instruction to be visited. This opcode is -++ * either NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, -++ * ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1, -++ * FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD, -++ * LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, -++ * IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, -++ * SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, -++ * DUP2_X2, SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, -++ * IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM, LREM, -++ * FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR, -++ * IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D, -++ * L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S, -++ * LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN, -++ * DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, -++ * or MONITOREXIT. -++ */ -++ public void visitInsn(int opcode) { -++ if (mv != null) { -++ mv.visitInsn(opcode); -++ } -++ } -++ -++ /** -++ * Visits an instruction with a single int operand. -++ * -++ * @param opcode -++ * the opcode of the instruction to be visited. This opcode is -++ * either BIPUSH, SIPUSH or NEWARRAY. -++ * @param operand -++ * the operand of the instruction to be visited.
-++ * When opcode is BIPUSH, operand value should be between -++ * Byte.MIN_VALUE and Byte.MAX_VALUE.
-++ * When opcode is SIPUSH, operand value should be between -++ * Short.MIN_VALUE and Short.MAX_VALUE.
-++ * When opcode is NEWARRAY, operand value should be one of -++ * {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR}, -++ * {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE}, -++ * {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT}, -++ * {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}. -++ */ -++ public void visitIntInsn(int opcode, int operand) { -++ if (mv != null) { -++ mv.visitIntInsn(opcode, operand); -++ } -++ } -++ -++ /** -++ * Visits a local variable instruction. A local variable instruction is an -++ * instruction that loads or stores the value of a local variable. -++ * -++ * @param opcode -++ * the opcode of the local variable instruction to be visited. -++ * This opcode is either ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, -++ * ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET. -++ * @param var -++ * the operand of the instruction to be visited. This operand is -++ * the index of a local variable. -++ */ -++ public void visitVarInsn(int opcode, int var) { -++ if (mv != null) { -++ mv.visitVarInsn(opcode, var); -++ } -++ } -++ -++ /** -++ * Visits a type instruction. A type instruction is an instruction that -++ * takes the internal name of a class as parameter. -++ * -++ * @param opcode -++ * the opcode of the type instruction to be visited. This opcode -++ * is either NEW, ANEWARRAY, CHECKCAST or INSTANCEOF. -++ * @param type -++ * the operand of the instruction to be visited. This operand -++ * must be the internal name of an object or array class (see -++ * {@link Type#getInternalName() getInternalName}). -++ */ -++ public void visitTypeInsn(int opcode, String type) { -++ if (mv != null) { -++ mv.visitTypeInsn(opcode, type); -++ } -++ } -++ -++ /** -++ * Visits a field instruction. A field instruction is an instruction that -++ * loads or stores the value of a field of an object. -++ * -++ * @param opcode -++ * the opcode of the type instruction to be visited. This opcode -++ * is either GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD. -++ * @param owner -++ * the internal name of the field's owner class (see -++ * {@link Type#getInternalName() getInternalName}). -++ * @param name -++ * the field's name. -++ * @param desc -++ * the field's descriptor (see {@link Type Type}). -++ */ -++ public void visitFieldInsn(int opcode, String owner, String name, -++ String desc) { -++ if (mv != null) { -++ mv.visitFieldInsn(opcode, owner, name, desc); -++ } -++ } -++ -++ /** -++ * Visits a method instruction. A method instruction is an instruction that -++ * invokes a method. -++ * -++ * @param opcode -++ * the opcode of the type instruction to be visited. This opcode -++ * is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or -++ * INVOKEINTERFACE. -++ * @param owner -++ * the internal name of the method's owner class (see -++ * {@link Type#getInternalName() getInternalName}). -++ * @param name -++ * the method's name. -++ * @param desc -++ * the method's descriptor (see {@link Type Type}). -++ */ -++ @Deprecated -++ public void visitMethodInsn(int opcode, String owner, String name, -++ String desc) { -++ if (api >= Opcodes.ASM5) { -++ boolean itf = opcode == Opcodes.INVOKEINTERFACE; -++ visitMethodInsn(opcode, owner, name, desc, itf); -++ return; -++ } -++ if (mv != null) { -++ mv.visitMethodInsn(opcode, owner, name, desc); -++ } -++ } -++ -++ /** -++ * Visits a method instruction. A method instruction is an instruction that -++ * invokes a method. -++ * -++ * @param opcode -++ * the opcode of the type instruction to be visited. This opcode -++ * is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or -++ * INVOKEINTERFACE. -++ * @param owner -++ * the internal name of the method's owner class (see -++ * {@link Type#getInternalName() getInternalName}). -++ * @param name -++ * the method's name. -++ * @param desc -++ * the method's descriptor (see {@link Type Type}). -++ * @param itf -++ * if the method's owner class is an interface. -++ */ -++ public void visitMethodInsn(int opcode, String owner, String name, -++ String desc, boolean itf) { -++ if (api < Opcodes.ASM5) { -++ if (itf != (opcode == Opcodes.INVOKEINTERFACE)) { -++ throw new IllegalArgumentException( -++ "INVOKESPECIAL/STATIC on interfaces require ASM 5"); -++ } -++ visitMethodInsn(opcode, owner, name, desc); -++ return; -++ } -++ if (mv != null) { -++ mv.visitMethodInsn(opcode, owner, name, desc, itf); -++ } -++ } -++ -++ /** -++ * Visits an invokedynamic instruction. -++ * -++ * @param name -++ * the method's name. -++ * @param desc -++ * the method's descriptor (see {@link Type Type}). -++ * @param bsm -++ * the bootstrap method. -++ * @param bsmArgs -++ * the bootstrap method constant arguments. Each argument must be -++ * an {@link Integer}, {@link Float}, {@link Long}, -++ * {@link Double}, {@link String}, {@link Type} or {@link Handle} -++ * value. This method is allowed to modify the content of the -++ * array so a caller should expect that this array may change. -++ */ -++ public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, -++ Object... bsmArgs) { -++ if (mv != null) { -++ mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); -++ } -++ } -++ -++ /** -++ * Visits a jump instruction. A jump instruction is an instruction that may -++ * jump to another instruction. -++ * -++ * @param opcode -++ * the opcode of the type instruction to be visited. This opcode -++ * is either IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, -++ * IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, -++ * IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL. -++ * @param label -++ * the operand of the instruction to be visited. This operand is -++ * a label that designates the instruction to which the jump -++ * instruction may jump. -++ */ -++ public void visitJumpInsn(int opcode, Label label) { -++ if (mv != null) { -++ mv.visitJumpInsn(opcode, label); -++ } -++ } -++ -++ /** -++ * Visits a label. A label designates the instruction that will be visited -++ * just after it. -++ * -++ * @param label -++ * a {@link Label Label} object. -++ */ -++ public void visitLabel(Label label) { -++ if (mv != null) { -++ mv.visitLabel(label); -++ } -++ } -++ -++ // ------------------------------------------------------------------------- -++ // Special instructions -++ // ------------------------------------------------------------------------- -++ -++ /** -++ * Visits a LDC instruction. Note that new constant types may be added in -++ * future versions of the Java Virtual Machine. To easily detect new -++ * constant types, implementations of this method should check for -++ * unexpected constant types, like this: -++ * -++ *
-++     * if (cst instanceof Integer) {
-++     *     // ...
-++     * } else if (cst instanceof Float) {
-++     *     // ...
-++     * } else if (cst instanceof Long) {
-++     *     // ...
-++     * } else if (cst instanceof Double) {
-++     *     // ...
-++     * } else if (cst instanceof String) {
-++     *     // ...
-++     * } else if (cst instanceof Type) {
-++     *     int sort = ((Type) cst).getSort();
-++     *     if (sort == Type.OBJECT) {
-++     *         // ...
-++     *     } else if (sort == Type.ARRAY) {
-++     *         // ...
-++     *     } else if (sort == Type.METHOD) {
-++     *         // ...
-++     *     } else {
-++     *         // throw an exception
-++     *     }
-++     * } else if (cst instanceof Handle) {
-++     *     // ...
-++     * } else {
-++     *     // throw an exception
-++     * }
-++     * 
-++ * -++ * @param cst -++ * the constant to be loaded on the stack. This parameter must be -++ * a non null {@link Integer}, a {@link Float}, a {@link Long}, a -++ * {@link Double}, a {@link String}, a {@link Type} of OBJECT or -++ * ARRAY sort for .class constants, for classes whose -++ * version is 49.0, a {@link Type} of METHOD sort or a -++ * {@link Handle} for MethodType and MethodHandle constants, for -++ * classes whose version is 51.0. -++ */ -++ public void visitLdcInsn(Object cst) { -++ if (mv != null) { -++ mv.visitLdcInsn(cst); -++ } -++ } -++ -++ /** -++ * Visits an IINC instruction. -++ * -++ * @param var -++ * index of the local variable to be incremented. -++ * @param increment -++ * amount to increment the local variable by. -++ */ -++ public void visitIincInsn(int var, int increment) { -++ if (mv != null) { -++ mv.visitIincInsn(var, increment); -++ } -++ } -++ -++ /** -++ * Visits a TABLESWITCH instruction. -++ * -++ * @param min -++ * the minimum key value. -++ * @param max -++ * the maximum key value. -++ * @param dflt -++ * beginning of the default handler block. -++ * @param labels -++ * beginnings of the handler blocks. labels[i] is the -++ * beginning of the handler block for the min + i key. -++ */ -++ public void visitTableSwitchInsn(int min, int max, Label dflt, -++ Label... labels) { -++ if (mv != null) { -++ mv.visitTableSwitchInsn(min, max, dflt, labels); -++ } -++ } -++ -++ /** -++ * Visits a LOOKUPSWITCH instruction. -++ * -++ * @param dflt -++ * beginning of the default handler block. -++ * @param keys -++ * the values of the keys. -++ * @param labels -++ * beginnings of the handler blocks. labels[i] is the -++ * beginning of the handler block for the keys[i] key. -++ */ -++ public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { -++ if (mv != null) { -++ mv.visitLookupSwitchInsn(dflt, keys, labels); -++ } -++ } -++ -++ /** -++ * Visits a MULTIANEWARRAY instruction. -++ * -++ * @param desc -++ * an array type descriptor (see {@link Type Type}). -++ * @param dims -++ * number of dimensions of the array to allocate. -++ */ -++ public void visitMultiANewArrayInsn(String desc, int dims) { -++ if (mv != null) { -++ mv.visitMultiANewArrayInsn(desc, dims); -++ } -++ } -++ -++ /** -++ * Visits an annotation on an instruction. This method must be called just -++ * after the annotated instruction. It can be called several times -++ * for the same instruction. -++ * -++ * @param typeRef -++ * a reference to the annotated type. The sort of this type -++ * reference must be {@link TypeReference#INSTANCEOF INSTANCEOF}, -++ * {@link TypeReference#NEW NEW}, -++ * {@link TypeReference#CONSTRUCTOR_REFERENCE -++ * CONSTRUCTOR_REFERENCE}, {@link TypeReference#METHOD_REFERENCE -++ * METHOD_REFERENCE}, {@link TypeReference#CAST CAST}, -++ * {@link TypeReference#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT -++ * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, -++ * {@link TypeReference#METHOD_INVOCATION_TYPE_ARGUMENT -++ * METHOD_INVOCATION_TYPE_ARGUMENT}, -++ * {@link TypeReference#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT -++ * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or -++ * {@link TypeReference#METHOD_REFERENCE_TYPE_ARGUMENT -++ * METHOD_REFERENCE_TYPE_ARGUMENT}. See {@link TypeReference}. -++ * @param typePath -++ * the path to the annotated type argument, wildcard bound, array -++ * element type, or static inner type within 'typeRef'. May be -++ * null if the annotation targets 'typeRef' as a whole. -++ * @param desc -++ * the class descriptor of the annotation class. -++ * @param visible -++ * true if the annotation is visible at runtime. -++ * @return a visitor to visit the annotation values, or null if -++ * this visitor is not interested in visiting this annotation. -++ */ -++ public AnnotationVisitor visitInsnAnnotation(int typeRef, -++ TypePath typePath, String desc, boolean visible) { -++ if (api < Opcodes.ASM5) { -++ throw new RuntimeException(); -++ } -++ if (mv != null) { -++ return mv.visitInsnAnnotation(typeRef, typePath, desc, visible); -++ } -++ return null; -++ } -++ -++ // ------------------------------------------------------------------------- -++ // Exceptions table entries, debug information, max stack and max locals -++ // ------------------------------------------------------------------------- -++ -++ /** -++ * Visits a try catch block. -++ * -++ * @param start -++ * beginning of the exception handler's scope (inclusive). -++ * @param end -++ * end of the exception handler's scope (exclusive). -++ * @param handler -++ * beginning of the exception handler's code. -++ * @param type -++ * internal name of the type of exceptions handled by the -++ * handler, or null to catch any exceptions (for -++ * "finally" blocks). -++ * @throws IllegalArgumentException -++ * if one of the labels has already been visited by this visitor -++ * (by the {@link #visitLabel visitLabel} method). -++ */ -++ public void visitTryCatchBlock(Label start, Label end, Label handler, -++ String type) { -++ if (mv != null) { -++ mv.visitTryCatchBlock(start, end, handler, type); -++ } -++ } -++ -++ /** -++ * Visits an annotation on an exception handler type. This method must be -++ * called after the {@link #visitTryCatchBlock} for the annotated -++ * exception handler. It can be called several times for the same exception -++ * handler. -++ * -++ * @param typeRef -++ * a reference to the annotated type. The sort of this type -++ * reference must be {@link TypeReference#EXCEPTION_PARAMETER -++ * EXCEPTION_PARAMETER}. See {@link TypeReference}. -++ * @param typePath -++ * the path to the annotated type argument, wildcard bound, array -++ * element type, or static inner type within 'typeRef'. May be -++ * null if the annotation targets 'typeRef' as a whole. -++ * @param desc -++ * the class descriptor of the annotation class. -++ * @param visible -++ * true if the annotation is visible at runtime. -++ * @return a visitor to visit the annotation values, or null if -++ * this visitor is not interested in visiting this annotation. -++ */ -++ public AnnotationVisitor visitTryCatchAnnotation(int typeRef, -++ TypePath typePath, String desc, boolean visible) { -++ if (api < Opcodes.ASM5) { -++ throw new RuntimeException(); -++ } -++ if (mv != null) { -++ return mv.visitTryCatchAnnotation(typeRef, typePath, desc, visible); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits a local variable declaration. -++ * -++ * @param name -++ * the name of a local variable. -++ * @param desc -++ * the type descriptor of this local variable. -++ * @param signature -++ * the type signature of this local variable. May be -++ * null if the local variable type does not use generic -++ * types. -++ * @param start -++ * the first instruction corresponding to the scope of this local -++ * variable (inclusive). -++ * @param end -++ * the last instruction corresponding to the scope of this local -++ * variable (exclusive). -++ * @param index -++ * the local variable's index. -++ * @throws IllegalArgumentException -++ * if one of the labels has not already been visited by this -++ * visitor (by the {@link #visitLabel visitLabel} method). -++ */ -++ public void visitLocalVariable(String name, String desc, String signature, -++ Label start, Label end, int index) { -++ if (mv != null) { -++ mv.visitLocalVariable(name, desc, signature, start, end, index); -++ } -++ } -++ -++ /** -++ * Visits an annotation on a local variable type. -++ * -++ * @param typeRef -++ * a reference to the annotated type. The sort of this type -++ * reference must be {@link TypeReference#LOCAL_VARIABLE -++ * LOCAL_VARIABLE} or {@link TypeReference#RESOURCE_VARIABLE -++ * RESOURCE_VARIABLE}. See {@link TypeReference}. -++ * @param typePath -++ * the path to the annotated type argument, wildcard bound, array -++ * element type, or static inner type within 'typeRef'. May be -++ * null if the annotation targets 'typeRef' as a whole. -++ * @param start -++ * the fist instructions corresponding to the continuous ranges -++ * that make the scope of this local variable (inclusive). -++ * @param end -++ * the last instructions corresponding to the continuous ranges -++ * that make the scope of this local variable (exclusive). This -++ * array must have the same size as the 'start' array. -++ * @param index -++ * the local variable's index in each range. This array must have -++ * the same size as the 'start' array. -++ * @param desc -++ * the class descriptor of the annotation class. -++ * @param visible -++ * true if the annotation is visible at runtime. -++ * @return a visitor to visit the annotation values, or null if -++ * this visitor is not interested in visiting this annotation. -++ */ -++ public AnnotationVisitor visitLocalVariableAnnotation(int typeRef, -++ TypePath typePath, Label[] start, Label[] end, int[] index, -++ String desc, boolean visible) { -++ if (api < Opcodes.ASM5) { -++ throw new RuntimeException(); -++ } -++ if (mv != null) { -++ return mv.visitLocalVariableAnnotation(typeRef, typePath, start, -++ end, index, desc, visible); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits a line number declaration. -++ * -++ * @param line -++ * a line number. This number refers to the source file from -++ * which the class was compiled. -++ * @param start -++ * the first instruction corresponding to this line number. -++ * @throws IllegalArgumentException -++ * if start has not already been visited by this -++ * visitor (by the {@link #visitLabel visitLabel} method). -++ */ -++ public void visitLineNumber(int line, Label start) { -++ if (mv != null) { -++ mv.visitLineNumber(line, start); -++ } -++ } -++ -++ /** -++ * Visits the maximum stack size and the maximum number of local variables -++ * of the method. -++ * -++ * @param maxStack -++ * maximum stack size of the method. -++ * @param maxLocals -++ * maximum number of local variables for the method. -++ */ -++ public void visitMaxs(int maxStack, int maxLocals) { -++ if (mv != null) { -++ mv.visitMaxs(maxStack, maxLocals); -++ } -++ } -++ -++ /** -++ * Visits the end of the method. This method, which is the last one to be -++ * called, is used to inform the visitor that all the annotations and -++ * attributes of the method have been visited. -++ */ -++ public void visitEnd() { -++ if (mv != null) { -++ mv.visitEnd(); -++ } -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/MethodWriter.java b/contrib/asm/src/org/objectweb/asm/MethodWriter.java -+new file mode 100644 -+index 0000000..ceca3f8 -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/MethodWriter.java -+@@ -0,0 +1,2915 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * A {@link MethodVisitor} that generates methods in bytecode form. Each visit -++ * method of this class appends the bytecode corresponding to the visited -++ * instruction to a byte vector, in the order these methods are called. -++ * -++ * @author Eric Bruneton -++ * @author Eugene Kuleshov -++ */ -++class MethodWriter extends MethodVisitor { -++ -++ /** -++ * Pseudo access flag used to denote constructors. -++ */ -++ static final int ACC_CONSTRUCTOR = 0x80000; -++ -++ /** -++ * Frame has exactly the same locals as the previous stack map frame and -++ * number of stack items is zero. -++ */ -++ static final int SAME_FRAME = 0; // to 63 (0-3f) -++ -++ /** -++ * Frame has exactly the same locals as the previous stack map frame and -++ * number of stack items is 1 -++ */ -++ static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; // to 127 (40-7f) -++ -++ /** -++ * Reserved for future use -++ */ -++ static final int RESERVED = 128; -++ -++ /** -++ * Frame has exactly the same locals as the previous stack map frame and -++ * number of stack items is 1. Offset is bigger then 63; -++ */ -++ static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; // f7 -++ -++ /** -++ * Frame where current locals are the same as the locals in the previous -++ * frame, except that the k last locals are absent. The value of k is given -++ * by the formula 251-frame_type. -++ */ -++ static final int CHOP_FRAME = 248; // to 250 (f8-fA) -++ -++ /** -++ * Frame has exactly the same locals as the previous stack map frame and -++ * number of stack items is zero. Offset is bigger then 63; -++ */ -++ static final int SAME_FRAME_EXTENDED = 251; // fb -++ -++ /** -++ * Frame where current locals are the same as the locals in the previous -++ * frame, except that k additional locals are defined. The value of k is -++ * given by the formula frame_type-251. -++ */ -++ static final int APPEND_FRAME = 252; // to 254 // fc-fe -++ -++ /** -++ * Full frame -++ */ -++ static final int FULL_FRAME = 255; // ff -++ -++ /** -++ * Indicates that the stack map frames must be recomputed from scratch. In -++ * this case the maximum stack size and number of local variables is also -++ * recomputed from scratch. -++ * -++ * @see #compute -++ */ -++ private static final int FRAMES = 0; -++ -++ /** -++ * Indicates that the maximum stack size and number of local variables must -++ * be automatically computed. -++ * -++ * @see #compute -++ */ -++ private static final int MAXS = 1; -++ -++ /** -++ * Indicates that nothing must be automatically computed. -++ * -++ * @see #compute -++ */ -++ private static final int NOTHING = 2; -++ -++ /** -++ * The class writer to which this method must be added. -++ */ -++ final ClassWriter cw; -++ -++ /** -++ * Access flags of this method. -++ */ -++ private int access; -++ -++ /** -++ * The index of the constant pool item that contains the name of this -++ * method. -++ */ -++ private final int name; -++ -++ /** -++ * The index of the constant pool item that contains the descriptor of this -++ * method. -++ */ -++ private final int desc; -++ -++ /** -++ * The descriptor of this method. -++ */ -++ private final String descriptor; -++ -++ /** -++ * The signature of this method. -++ */ -++ String signature; -++ -++ /** -++ * If not zero, indicates that the code of this method must be copied from -++ * the ClassReader associated to this writer in cw.cr. More -++ * precisely, this field gives the index of the first byte to copied from -++ * cw.cr.b. -++ */ -++ int classReaderOffset; -++ -++ /** -++ * If not zero, indicates that the code of this method must be copied from -++ * the ClassReader associated to this writer in cw.cr. More -++ * precisely, this field gives the number of bytes to copied from -++ * cw.cr.b. -++ */ -++ int classReaderLength; -++ -++ /** -++ * Number of exceptions that can be thrown by this method. -++ */ -++ int exceptionCount; -++ -++ /** -++ * The exceptions that can be thrown by this method. More precisely, this -++ * array contains the indexes of the constant pool items that contain the -++ * internal names of these exception classes. -++ */ -++ int[] exceptions; -++ -++ /** -++ * The annotation default attribute of this method. May be null. -++ */ -++ private ByteVector annd; -++ -++ /** -++ * The runtime visible annotations of this method. May be null. -++ */ -++ private AnnotationWriter anns; -++ -++ /** -++ * The runtime invisible annotations of this method. May be null. -++ */ -++ private AnnotationWriter ianns; -++ -++ /** -++ * The runtime visible type annotations of this method. May be null -++ * . -++ */ -++ private AnnotationWriter tanns; -++ -++ /** -++ * The runtime invisible type annotations of this method. May be -++ * null. -++ */ -++ private AnnotationWriter itanns; -++ -++ /** -++ * The runtime visible parameter annotations of this method. May be -++ * null. -++ */ -++ private AnnotationWriter[] panns; -++ -++ /** -++ * The runtime invisible parameter annotations of this method. May be -++ * null. -++ */ -++ private AnnotationWriter[] ipanns; -++ -++ /** -++ * The number of synthetic parameters of this method. -++ */ -++ private int synthetics; -++ -++ /** -++ * The non standard attributes of the method. -++ */ -++ private Attribute attrs; -++ -++ /** -++ * The bytecode of this method. -++ */ -++ private ByteVector code = new ByteVector(); -++ -++ /** -++ * Maximum stack size of this method. -++ */ -++ private int maxStack; -++ -++ /** -++ * Maximum number of local variables for this method. -++ */ -++ private int maxLocals; -++ -++ /** -++ * Number of local variables in the current stack map frame. -++ */ -++ private int currentLocals; -++ -++ /** -++ * Number of stack map frames in the StackMapTable attribute. -++ */ -++ private int frameCount; -++ -++ /** -++ * The StackMapTable attribute. -++ */ -++ private ByteVector stackMap; -++ -++ /** -++ * The offset of the last frame that was written in the StackMapTable -++ * attribute. -++ */ -++ private int previousFrameOffset; -++ -++ /** -++ * The last frame that was written in the StackMapTable attribute. -++ * -++ * @see #frame -++ */ -++ private int[] previousFrame; -++ -++ /** -++ * The current stack map frame. The first element contains the offset of the -++ * instruction to which the frame corresponds, the second element is the -++ * number of locals and the third one is the number of stack elements. The -++ * local variables start at index 3 and are followed by the operand stack -++ * values. In summary frame[0] = offset, frame[1] = nLocal, frame[2] = -++ * nStack, frame[3] = nLocal. All types are encoded as integers, with the -++ * same format as the one used in {@link Label}, but limited to BASE types. -++ */ -++ private int[] frame; -++ -++ /** -++ * Number of elements in the exception handler list. -++ */ -++ private int handlerCount; -++ -++ /** -++ * The first element in the exception handler list. -++ */ -++ private Handler firstHandler; -++ -++ /** -++ * The last element in the exception handler list. -++ */ -++ private Handler lastHandler; -++ -++ /** -++ * Number of entries in the MethodParameters attribute. -++ */ -++ private int methodParametersCount; -++ -++ /** -++ * The MethodParameters attribute. -++ */ -++ private ByteVector methodParameters; -++ -++ /** -++ * Number of entries in the LocalVariableTable attribute. -++ */ -++ private int localVarCount; -++ -++ /** -++ * The LocalVariableTable attribute. -++ */ -++ private ByteVector localVar; -++ -++ /** -++ * Number of entries in the LocalVariableTypeTable attribute. -++ */ -++ private int localVarTypeCount; -++ -++ /** -++ * The LocalVariableTypeTable attribute. -++ */ -++ private ByteVector localVarType; -++ -++ /** -++ * Number of entries in the LineNumberTable attribute. -++ */ -++ private int lineNumberCount; -++ -++ /** -++ * The LineNumberTable attribute. -++ */ -++ private ByteVector lineNumber; -++ -++ /** -++ * The start offset of the last visited instruction. -++ */ -++ private int lastCodeOffset; -++ -++ /** -++ * The runtime visible type annotations of the code. May be null. -++ */ -++ private AnnotationWriter ctanns; -++ -++ /** -++ * The runtime invisible type annotations of the code. May be null. -++ */ -++ private AnnotationWriter ictanns; -++ -++ /** -++ * The non standard attributes of the method's code. -++ */ -++ private Attribute cattrs; -++ -++ /** -++ * Indicates if some jump instructions are too small and need to be resized. -++ */ -++ private boolean resize; -++ -++ /** -++ * The number of subroutines in this method. -++ */ -++ private int subroutines; -++ -++ // ------------------------------------------------------------------------ -++ -++ /* -++ * Fields for the control flow graph analysis algorithm (used to compute the -++ * maximum stack size). A control flow graph contains one node per "basic -++ * block", and one edge per "jump" from one basic block to another. Each -++ * node (i.e., each basic block) is represented by the Label object that -++ * corresponds to the first instruction of this basic block. Each node also -++ * stores the list of its successors in the graph, as a linked list of Edge -++ * objects. -++ */ -++ -++ /** -++ * Indicates what must be automatically computed. -++ * -++ * @see #FRAMES -++ * @see #MAXS -++ * @see #NOTHING -++ */ -++ private final int compute; -++ -++ /** -++ * A list of labels. This list is the list of basic blocks in the method, -++ * i.e. a list of Label objects linked to each other by their -++ * {@link Label#successor} field, in the order they are visited by -++ * {@link MethodVisitor#visitLabel}, and starting with the first basic -++ * block. -++ */ -++ private Label labels; -++ -++ /** -++ * The previous basic block. -++ */ -++ private Label previousBlock; -++ -++ /** -++ * The current basic block. -++ */ -++ private Label currentBlock; -++ -++ /** -++ * The (relative) stack size after the last visited instruction. This size -++ * is relative to the beginning of the current basic block, i.e., the true -++ * stack size after the last visited instruction is equal to the -++ * {@link Label#inputStackTop beginStackSize} of the current basic block -++ * plus stackSize. -++ */ -++ private int stackSize; -++ -++ /** -++ * The (relative) maximum stack size after the last visited instruction. -++ * This size is relative to the beginning of the current basic block, i.e., -++ * the true maximum stack size after the last visited instruction is equal -++ * to the {@link Label#inputStackTop beginStackSize} of the current basic -++ * block plus stackSize. -++ */ -++ private int maxStackSize; -++ -++ // ------------------------------------------------------------------------ -++ // Constructor -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Constructs a new {@link MethodWriter}. -++ * -++ * @param cw -++ * the class writer in which the method must be added. -++ * @param access -++ * the method's access flags (see {@link Opcodes}). -++ * @param name -++ * the method's name. -++ * @param desc -++ * the method's descriptor (see {@link Type}). -++ * @param signature -++ * the method's signature. May be null. -++ * @param exceptions -++ * the internal names of the method's exceptions. May be -++ * null. -++ * @param computeMaxs -++ * true if the maximum stack size and number of local -++ * variables must be automatically computed. -++ * @param computeFrames -++ * true if the stack map tables must be recomputed from -++ * scratch. -++ */ -++ MethodWriter(final ClassWriter cw, final int access, final String name, -++ final String desc, final String signature, -++ final String[] exceptions, final boolean computeMaxs, -++ final boolean computeFrames) { -++ super(Opcodes.ASM5); -++ if (cw.firstMethod == null) { -++ cw.firstMethod = this; -++ } else { -++ cw.lastMethod.mv = this; -++ } -++ cw.lastMethod = this; -++ this.cw = cw; -++ this.access = access; -++ if ("".equals(name)) { -++ this.access |= ACC_CONSTRUCTOR; -++ } -++ this.name = cw.newUTF8(name); -++ this.desc = cw.newUTF8(desc); -++ this.descriptor = desc; -++ if (ClassReader.SIGNATURES) { -++ this.signature = signature; -++ } -++ if (exceptions != null && exceptions.length > 0) { -++ exceptionCount = exceptions.length; -++ this.exceptions = new int[exceptionCount]; -++ for (int i = 0; i < exceptionCount; ++i) { -++ this.exceptions[i] = cw.newClass(exceptions[i]); -++ } -++ } -++ this.compute = computeFrames ? FRAMES : (computeMaxs ? MAXS : NOTHING); -++ if (computeMaxs || computeFrames) { -++ // updates maxLocals -++ int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2; -++ if ((access & Opcodes.ACC_STATIC) != 0) { -++ --size; -++ } -++ maxLocals = size; -++ currentLocals = size; -++ // creates and visits the label for the first basic block -++ labels = new Label(); -++ labels.status |= Label.PUSHED; -++ visitLabel(labels); -++ } -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Implementation of the MethodVisitor abstract class -++ // ------------------------------------------------------------------------ -++ -++ @Override -++ public void visitParameter(String name, int access) { -++ if (methodParameters == null) { -++ methodParameters = new ByteVector(); -++ } -++ ++methodParametersCount; -++ methodParameters.putShort((name == null) ? 0 : cw.newUTF8(name)) -++ .putShort(access); -++ } -++ -++ @Override -++ public AnnotationVisitor visitAnnotationDefault() { -++ if (!ClassReader.ANNOTATIONS) { -++ return null; -++ } -++ annd = new ByteVector(); -++ return new AnnotationWriter(cw, false, annd, null, 0); -++ } -++ -++ @Override -++ public AnnotationVisitor visitAnnotation(final String desc, -++ final boolean visible) { -++ if (!ClassReader.ANNOTATIONS) { -++ return null; -++ } -++ ByteVector bv = new ByteVector(); -++ // write type, and reserve space for values count -++ bv.putShort(cw.newUTF8(desc)).putShort(0); -++ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); -++ if (visible) { -++ aw.next = anns; -++ anns = aw; -++ } else { -++ aw.next = ianns; -++ ianns = aw; -++ } -++ return aw; -++ } -++ -++ @Override -++ public AnnotationVisitor visitTypeAnnotation(final int typeRef, -++ final TypePath typePath, final String desc, final boolean visible) { -++ if (!ClassReader.ANNOTATIONS) { -++ return null; -++ } -++ ByteVector bv = new ByteVector(); -++ // write target_type and target_info -++ AnnotationWriter.putTarget(typeRef, typePath, bv); -++ // write type, and reserve space for values count -++ bv.putShort(cw.newUTF8(desc)).putShort(0); -++ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, -++ bv.length - 2); -++ if (visible) { -++ aw.next = tanns; -++ tanns = aw; -++ } else { -++ aw.next = itanns; -++ itanns = aw; -++ } -++ return aw; -++ } -++ -++ @Override -++ public AnnotationVisitor visitParameterAnnotation(final int parameter, -++ final String desc, final boolean visible) { -++ if (!ClassReader.ANNOTATIONS) { -++ return null; -++ } -++ ByteVector bv = new ByteVector(); -++ if ("Ljava/lang/Synthetic;".equals(desc)) { -++ // workaround for a bug in javac with synthetic parameters -++ // see ClassReader.readParameterAnnotations -++ synthetics = Math.max(synthetics, parameter + 1); -++ return new AnnotationWriter(cw, false, bv, null, 0); -++ } -++ // write type, and reserve space for values count -++ bv.putShort(cw.newUTF8(desc)).putShort(0); -++ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); -++ if (visible) { -++ if (panns == null) { -++ panns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; -++ } -++ aw.next = panns[parameter]; -++ panns[parameter] = aw; -++ } else { -++ if (ipanns == null) { -++ ipanns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; -++ } -++ aw.next = ipanns[parameter]; -++ ipanns[parameter] = aw; -++ } -++ return aw; -++ } -++ -++ @Override -++ public void visitAttribute(final Attribute attr) { -++ if (attr.isCodeAttribute()) { -++ attr.next = cattrs; -++ cattrs = attr; -++ } else { -++ attr.next = attrs; -++ attrs = attr; -++ } -++ } -++ -++ @Override -++ public void visitCode() { -++ } -++ -++ @Override -++ public void visitFrame(final int type, final int nLocal, -++ final Object[] local, final int nStack, final Object[] stack) { -++ if (!ClassReader.FRAMES || compute == FRAMES) { -++ return; -++ } -++ -++ if (type == Opcodes.F_NEW) { -++ if (previousFrame == null) { -++ visitImplicitFirstFrame(); -++ } -++ currentLocals = nLocal; -++ int frameIndex = startFrame(code.length, nLocal, nStack); -++ for (int i = 0; i < nLocal; ++i) { -++ if (local[i] instanceof String) { -++ frame[frameIndex++] = Frame.OBJECT -++ | cw.addType((String) local[i]); -++ } else if (local[i] instanceof Integer) { -++ frame[frameIndex++] = ((Integer) local[i]).intValue(); -++ } else { -++ frame[frameIndex++] = Frame.UNINITIALIZED -++ | cw.addUninitializedType("", -++ ((Label) local[i]).position); -++ } -++ } -++ for (int i = 0; i < nStack; ++i) { -++ if (stack[i] instanceof String) { -++ frame[frameIndex++] = Frame.OBJECT -++ | cw.addType((String) stack[i]); -++ } else if (stack[i] instanceof Integer) { -++ frame[frameIndex++] = ((Integer) stack[i]).intValue(); -++ } else { -++ frame[frameIndex++] = Frame.UNINITIALIZED -++ | cw.addUninitializedType("", -++ ((Label) stack[i]).position); -++ } -++ } -++ endFrame(); -++ } else { -++ int delta; -++ if (stackMap == null) { -++ stackMap = new ByteVector(); -++ delta = code.length; -++ } else { -++ delta = code.length - previousFrameOffset - 1; -++ if (delta < 0) { -++ if (type == Opcodes.F_SAME) { -++ return; -++ } else { -++ throw new IllegalStateException(); -++ } -++ } -++ } -++ -++ switch (type) { -++ case Opcodes.F_FULL: -++ currentLocals = nLocal; -++ stackMap.putByte(FULL_FRAME).putShort(delta).putShort(nLocal); -++ for (int i = 0; i < nLocal; ++i) { -++ writeFrameType(local[i]); -++ } -++ stackMap.putShort(nStack); -++ for (int i = 0; i < nStack; ++i) { -++ writeFrameType(stack[i]); -++ } -++ break; -++ case Opcodes.F_APPEND: -++ currentLocals += nLocal; -++ stackMap.putByte(SAME_FRAME_EXTENDED + nLocal).putShort(delta); -++ for (int i = 0; i < nLocal; ++i) { -++ writeFrameType(local[i]); -++ } -++ break; -++ case Opcodes.F_CHOP: -++ currentLocals -= nLocal; -++ stackMap.putByte(SAME_FRAME_EXTENDED - nLocal).putShort(delta); -++ break; -++ case Opcodes.F_SAME: -++ if (delta < 64) { -++ stackMap.putByte(delta); -++ } else { -++ stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta); -++ } -++ break; -++ case Opcodes.F_SAME1: -++ if (delta < 64) { -++ stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); -++ } else { -++ stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) -++ .putShort(delta); -++ } -++ writeFrameType(stack[0]); -++ break; -++ } -++ -++ previousFrameOffset = code.length; -++ ++frameCount; -++ } -++ -++ maxStack = Math.max(maxStack, nStack); -++ maxLocals = Math.max(maxLocals, currentLocals); -++ } -++ -++ @Override -++ public void visitInsn(final int opcode) { -++ lastCodeOffset = code.length; -++ // adds the instruction to the bytecode of the method -++ code.putByte(opcode); -++ // update currentBlock -++ // Label currentBlock = this.currentBlock; -++ if (currentBlock != null) { -++ if (compute == FRAMES) { -++ currentBlock.frame.execute(opcode, 0, null, null); -++ } else { -++ // updates current and max stack sizes -++ int size = stackSize + Frame.SIZE[opcode]; -++ if (size > maxStackSize) { -++ maxStackSize = size; -++ } -++ stackSize = size; -++ } -++ // if opcode == ATHROW or xRETURN, ends current block (no successor) -++ if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) -++ || opcode == Opcodes.ATHROW) { -++ noSuccessor(); -++ } -++ } -++ } -++ -++ @Override -++ public void visitIntInsn(final int opcode, final int operand) { -++ lastCodeOffset = code.length; -++ // Label currentBlock = this.currentBlock; -++ if (currentBlock != null) { -++ if (compute == FRAMES) { -++ currentBlock.frame.execute(opcode, operand, null, null); -++ } else if (opcode != Opcodes.NEWARRAY) { -++ // updates current and max stack sizes only for NEWARRAY -++ // (stack size variation = 0 for BIPUSH or SIPUSH) -++ int size = stackSize + 1; -++ if (size > maxStackSize) { -++ maxStackSize = size; -++ } -++ stackSize = size; -++ } -++ } -++ // adds the instruction to the bytecode of the method -++ if (opcode == Opcodes.SIPUSH) { -++ code.put12(opcode, operand); -++ } else { // BIPUSH or NEWARRAY -++ code.put11(opcode, operand); -++ } -++ } -++ -++ @Override -++ public void visitVarInsn(final int opcode, final int var) { -++ lastCodeOffset = code.length; -++ // Label currentBlock = this.currentBlock; -++ if (currentBlock != null) { -++ if (compute == FRAMES) { -++ currentBlock.frame.execute(opcode, var, null, null); -++ } else { -++ // updates current and max stack sizes -++ if (opcode == Opcodes.RET) { -++ // no stack change, but end of current block (no successor) -++ currentBlock.status |= Label.RET; -++ // save 'stackSize' here for future use -++ // (see {@link #findSubroutineSuccessors}) -++ currentBlock.inputStackTop = stackSize; -++ noSuccessor(); -++ } else { // xLOAD or xSTORE -++ int size = stackSize + Frame.SIZE[opcode]; -++ if (size > maxStackSize) { -++ maxStackSize = size; -++ } -++ stackSize = size; -++ } -++ } -++ } -++ if (compute != NOTHING) { -++ // updates max locals -++ int n; -++ if (opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD -++ || opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE) { -++ n = var + 2; -++ } else { -++ n = var + 1; -++ } -++ if (n > maxLocals) { -++ maxLocals = n; -++ } -++ } -++ // adds the instruction to the bytecode of the method -++ if (var < 4 && opcode != Opcodes.RET) { -++ int opt; -++ if (opcode < Opcodes.ISTORE) { -++ /* ILOAD_0 */ -++ opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var; -++ } else { -++ /* ISTORE_0 */ -++ opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var; -++ } -++ code.putByte(opt); -++ } else if (var >= 256) { -++ code.putByte(196 /* WIDE */).put12(opcode, var); -++ } else { -++ code.put11(opcode, var); -++ } -++ if (opcode >= Opcodes.ISTORE && compute == FRAMES && handlerCount > 0) { -++ visitLabel(new Label()); -++ } -++ } -++ -++ @Override -++ public void visitTypeInsn(final int opcode, final String type) { -++ lastCodeOffset = code.length; -++ Item i = cw.newClassItem(type); -++ // Label currentBlock = this.currentBlock; -++ if (currentBlock != null) { -++ if (compute == FRAMES) { -++ currentBlock.frame.execute(opcode, code.length, cw, i); -++ } else if (opcode == Opcodes.NEW) { -++ // updates current and max stack sizes only if opcode == NEW -++ // (no stack change for ANEWARRAY, CHECKCAST, INSTANCEOF) -++ int size = stackSize + 1; -++ if (size > maxStackSize) { -++ maxStackSize = size; -++ } -++ stackSize = size; -++ } -++ } -++ // adds the instruction to the bytecode of the method -++ code.put12(opcode, i.index); -++ } -++ -++ @Override -++ public void visitFieldInsn(final int opcode, final String owner, -++ final String name, final String desc) { -++ lastCodeOffset = code.length; -++ Item i = cw.newFieldItem(owner, name, desc); -++ // Label currentBlock = this.currentBlock; -++ if (currentBlock != null) { -++ if (compute == FRAMES) { -++ currentBlock.frame.execute(opcode, 0, cw, i); -++ } else { -++ int size; -++ // computes the stack size variation -++ char c = desc.charAt(0); -++ switch (opcode) { -++ case Opcodes.GETSTATIC: -++ size = stackSize + (c == 'D' || c == 'J' ? 2 : 1); -++ break; -++ case Opcodes.PUTSTATIC: -++ size = stackSize + (c == 'D' || c == 'J' ? -2 : -1); -++ break; -++ case Opcodes.GETFIELD: -++ size = stackSize + (c == 'D' || c == 'J' ? 1 : 0); -++ break; -++ // case Constants.PUTFIELD: -++ default: -++ size = stackSize + (c == 'D' || c == 'J' ? -3 : -2); -++ break; -++ } -++ // updates current and max stack sizes -++ if (size > maxStackSize) { -++ maxStackSize = size; -++ } -++ stackSize = size; -++ } -++ } -++ // adds the instruction to the bytecode of the method -++ code.put12(opcode, i.index); -++ } -++ -++ @Override -++ public void visitMethodInsn(final int opcode, final String owner, -++ final String name, final String desc, final boolean itf) { -++ lastCodeOffset = code.length; -++ Item i = cw.newMethodItem(owner, name, desc, itf); -++ int argSize = i.intVal; -++ // Label currentBlock = this.currentBlock; -++ if (currentBlock != null) { -++ if (compute == FRAMES) { -++ currentBlock.frame.execute(opcode, 0, cw, i); -++ } else { -++ /* -++ * computes the stack size variation. In order not to recompute -++ * several times this variation for the same Item, we use the -++ * intVal field of this item to store this variation, once it -++ * has been computed. More precisely this intVal field stores -++ * the sizes of the arguments and of the return value -++ * corresponding to desc. -++ */ -++ if (argSize == 0) { -++ // the above sizes have not been computed yet, -++ // so we compute them... -++ argSize = Type.getArgumentsAndReturnSizes(desc); -++ // ... and we save them in order -++ // not to recompute them in the future -++ i.intVal = argSize; -++ } -++ int size; -++ if (opcode == Opcodes.INVOKESTATIC) { -++ size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1; -++ } else { -++ size = stackSize - (argSize >> 2) + (argSize & 0x03); -++ } -++ // updates current and max stack sizes -++ if (size > maxStackSize) { -++ maxStackSize = size; -++ } -++ stackSize = size; -++ } -++ } -++ // adds the instruction to the bytecode of the method -++ if (opcode == Opcodes.INVOKEINTERFACE) { -++ if (argSize == 0) { -++ argSize = Type.getArgumentsAndReturnSizes(desc); -++ i.intVal = argSize; -++ } -++ code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0); -++ } else { -++ code.put12(opcode, i.index); -++ } -++ } -++ -++ @Override -++ public void visitInvokeDynamicInsn(final String name, final String desc, -++ final Handle bsm, final Object... bsmArgs) { -++ lastCodeOffset = code.length; -++ Item i = cw.newInvokeDynamicItem(name, desc, bsm, bsmArgs); -++ int argSize = i.intVal; -++ // Label currentBlock = this.currentBlock; -++ if (currentBlock != null) { -++ if (compute == FRAMES) { -++ currentBlock.frame.execute(Opcodes.INVOKEDYNAMIC, 0, cw, i); -++ } else { -++ /* -++ * computes the stack size variation. In order not to recompute -++ * several times this variation for the same Item, we use the -++ * intVal field of this item to store this variation, once it -++ * has been computed. More precisely this intVal field stores -++ * the sizes of the arguments and of the return value -++ * corresponding to desc. -++ */ -++ if (argSize == 0) { -++ // the above sizes have not been computed yet, -++ // so we compute them... -++ argSize = Type.getArgumentsAndReturnSizes(desc); -++ // ... and we save them in order -++ // not to recompute them in the future -++ i.intVal = argSize; -++ } -++ int size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1; -++ -++ // updates current and max stack sizes -++ if (size > maxStackSize) { -++ maxStackSize = size; -++ } -++ stackSize = size; -++ } -++ } -++ // adds the instruction to the bytecode of the method -++ code.put12(Opcodes.INVOKEDYNAMIC, i.index); -++ code.putShort(0); -++ } -++ -++ @Override -++ public void visitJumpInsn(final int opcode, final Label label) { -++ lastCodeOffset = code.length; -++ Label nextInsn = null; -++ // Label currentBlock = this.currentBlock; -++ if (currentBlock != null) { -++ if (compute == FRAMES) { -++ currentBlock.frame.execute(opcode, 0, null, null); -++ // 'label' is the target of a jump instruction -++ label.getFirst().status |= Label.TARGET; -++ // adds 'label' as a successor of this basic block -++ addSuccessor(Edge.NORMAL, label); -++ if (opcode != Opcodes.GOTO) { -++ // creates a Label for the next basic block -++ nextInsn = new Label(); -++ } -++ } else { -++ if (opcode == Opcodes.JSR) { -++ if ((label.status & Label.SUBROUTINE) == 0) { -++ label.status |= Label.SUBROUTINE; -++ ++subroutines; -++ } -++ currentBlock.status |= Label.JSR; -++ addSuccessor(stackSize + 1, label); -++ // creates a Label for the next basic block -++ nextInsn = new Label(); -++ /* -++ * note that, by construction in this method, a JSR block -++ * has at least two successors in the control flow graph: -++ * the first one leads the next instruction after the JSR, -++ * while the second one leads to the JSR target. -++ */ -++ } else { -++ // updates current stack size (max stack size unchanged -++ // because stack size variation always negative in this -++ // case) -++ stackSize += Frame.SIZE[opcode]; -++ addSuccessor(stackSize, label); -++ } -++ } -++ } -++ // adds the instruction to the bytecode of the method -++ if ((label.status & Label.RESOLVED) != 0 -++ && label.position - code.length < Short.MIN_VALUE) { -++ /* -++ * case of a backward jump with an offset < -32768. In this case we -++ * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx -++ * with IFNOTxxx GOTO_W , where IFNOTxxx is the -++ * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where -++ * designates the instruction just after the GOTO_W. -++ */ -++ if (opcode == Opcodes.GOTO) { -++ code.putByte(200); // GOTO_W -++ } else if (opcode == Opcodes.JSR) { -++ code.putByte(201); // JSR_W -++ } else { -++ // if the IF instruction is transformed into IFNOT GOTO_W the -++ // next instruction becomes the target of the IFNOT instruction -++ if (nextInsn != null) { -++ nextInsn.status |= Label.TARGET; -++ } -++ code.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 -++ : opcode ^ 1); -++ code.putShort(8); // jump offset -++ code.putByte(200); // GOTO_W -++ } -++ label.put(this, code, code.length - 1, true); -++ } else { -++ /* -++ * case of a backward jump with an offset >= -32768, or of a forward -++ * jump with, of course, an unknown offset. In these cases we store -++ * the offset in 2 bytes (which will be increased in -++ * resizeInstructions, if needed). -++ */ -++ code.putByte(opcode); -++ label.put(this, code, code.length - 1, false); -++ } -++ if (currentBlock != null) { -++ if (nextInsn != null) { -++ // if the jump instruction is not a GOTO, the next instruction -++ // is also a successor of this instruction. Calling visitLabel -++ // adds the label of this next instruction as a successor of the -++ // current block, and starts a new basic block -++ visitLabel(nextInsn); -++ } -++ if (opcode == Opcodes.GOTO) { -++ noSuccessor(); -++ } -++ } -++ } -++ -++ @Override -++ public void visitLabel(final Label label) { -++ // resolves previous forward references to label, if any -++ resize |= label.resolve(this, code.length, code.data); -++ // updates currentBlock -++ if ((label.status & Label.DEBUG) != 0) { -++ return; -++ } -++ if (compute == FRAMES) { -++ if (currentBlock != null) { -++ if (label.position == currentBlock.position) { -++ // successive labels, do not start a new basic block -++ currentBlock.status |= (label.status & Label.TARGET); -++ label.frame = currentBlock.frame; -++ return; -++ } -++ // ends current block (with one new successor) -++ addSuccessor(Edge.NORMAL, label); -++ } -++ // begins a new current block -++ currentBlock = label; -++ if (label.frame == null) { -++ label.frame = new Frame(); -++ label.frame.owner = label; -++ } -++ // updates the basic block list -++ if (previousBlock != null) { -++ if (label.position == previousBlock.position) { -++ previousBlock.status |= (label.status & Label.TARGET); -++ label.frame = previousBlock.frame; -++ currentBlock = previousBlock; -++ return; -++ } -++ previousBlock.successor = label; -++ } -++ previousBlock = label; -++ } else if (compute == MAXS) { -++ if (currentBlock != null) { -++ // ends current block (with one new successor) -++ currentBlock.outputStackMax = maxStackSize; -++ addSuccessor(stackSize, label); -++ } -++ // begins a new current block -++ currentBlock = label; -++ // resets the relative current and max stack sizes -++ stackSize = 0; -++ maxStackSize = 0; -++ // updates the basic block list -++ if (previousBlock != null) { -++ previousBlock.successor = label; -++ } -++ previousBlock = label; -++ } -++ } -++ -++ @Override -++ public void visitLdcInsn(final Object cst) { -++ lastCodeOffset = code.length; -++ Item i = cw.newConstItem(cst); -++ // Label currentBlock = this.currentBlock; -++ if (currentBlock != null) { -++ if (compute == FRAMES) { -++ currentBlock.frame.execute(Opcodes.LDC, 0, cw, i); -++ } else { -++ int size; -++ // computes the stack size variation -++ if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) { -++ size = stackSize + 2; -++ } else { -++ size = stackSize + 1; -++ } -++ // updates current and max stack sizes -++ if (size > maxStackSize) { -++ maxStackSize = size; -++ } -++ stackSize = size; -++ } -++ } -++ // adds the instruction to the bytecode of the method -++ int index = i.index; -++ if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) { -++ code.put12(20 /* LDC2_W */, index); -++ } else if (index >= 256) { -++ code.put12(19 /* LDC_W */, index); -++ } else { -++ code.put11(Opcodes.LDC, index); -++ } -++ } -++ -++ @Override -++ public void visitIincInsn(final int var, final int increment) { -++ lastCodeOffset = code.length; -++ if (currentBlock != null) { -++ if (compute == FRAMES) { -++ currentBlock.frame.execute(Opcodes.IINC, var, null, null); -++ } -++ } -++ if (compute != NOTHING) { -++ // updates max locals -++ int n = var + 1; -++ if (n > maxLocals) { -++ maxLocals = n; -++ } -++ } -++ // adds the instruction to the bytecode of the method -++ if ((var > 255) || (increment > 127) || (increment < -128)) { -++ code.putByte(196 /* WIDE */).put12(Opcodes.IINC, var) -++ .putShort(increment); -++ } else { -++ code.putByte(Opcodes.IINC).put11(var, increment); -++ } -++ } -++ -++ @Override -++ public void visitTableSwitchInsn(final int min, final int max, -++ final Label dflt, final Label... labels) { -++ lastCodeOffset = code.length; -++ // adds the instruction to the bytecode of the method -++ int source = code.length; -++ code.putByte(Opcodes.TABLESWITCH); -++ code.putByteArray(null, 0, (4 - code.length % 4) % 4); -++ dflt.put(this, code, source, true); -++ code.putInt(min).putInt(max); -++ for (int i = 0; i < labels.length; ++i) { -++ labels[i].put(this, code, source, true); -++ } -++ // updates currentBlock -++ visitSwitchInsn(dflt, labels); -++ } -++ -++ @Override -++ public void visitLookupSwitchInsn(final Label dflt, final int[] keys, -++ final Label[] labels) { -++ lastCodeOffset = code.length; -++ // adds the instruction to the bytecode of the method -++ int source = code.length; -++ code.putByte(Opcodes.LOOKUPSWITCH); -++ code.putByteArray(null, 0, (4 - code.length % 4) % 4); -++ dflt.put(this, code, source, true); -++ code.putInt(labels.length); -++ for (int i = 0; i < labels.length; ++i) { -++ code.putInt(keys[i]); -++ labels[i].put(this, code, source, true); -++ } -++ // updates currentBlock -++ visitSwitchInsn(dflt, labels); -++ } -++ -++ private void visitSwitchInsn(final Label dflt, final Label[] labels) { -++ // Label currentBlock = this.currentBlock; -++ if (currentBlock != null) { -++ if (compute == FRAMES) { -++ currentBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0, null, null); -++ // adds current block successors -++ addSuccessor(Edge.NORMAL, dflt); -++ dflt.getFirst().status |= Label.TARGET; -++ for (int i = 0; i < labels.length; ++i) { -++ addSuccessor(Edge.NORMAL, labels[i]); -++ labels[i].getFirst().status |= Label.TARGET; -++ } -++ } else { -++ // updates current stack size (max stack size unchanged) -++ --stackSize; -++ // adds current block successors -++ addSuccessor(stackSize, dflt); -++ for (int i = 0; i < labels.length; ++i) { -++ addSuccessor(stackSize, labels[i]); -++ } -++ } -++ // ends current block -++ noSuccessor(); -++ } -++ } -++ -++ @Override -++ public void visitMultiANewArrayInsn(final String desc, final int dims) { -++ lastCodeOffset = code.length; -++ Item i = cw.newClassItem(desc); -++ // Label currentBlock = this.currentBlock; -++ if (currentBlock != null) { -++ if (compute == FRAMES) { -++ currentBlock.frame.execute(Opcodes.MULTIANEWARRAY, dims, cw, i); -++ } else { -++ // updates current stack size (max stack size unchanged because -++ // stack size variation always negative or null) -++ stackSize += 1 - dims; -++ } -++ } -++ // adds the instruction to the bytecode of the method -++ code.put12(Opcodes.MULTIANEWARRAY, i.index).putByte(dims); -++ } -++ -++ @Override -++ public AnnotationVisitor visitInsnAnnotation(int typeRef, -++ TypePath typePath, String desc, boolean visible) { -++ if (!ClassReader.ANNOTATIONS) { -++ return null; -++ } -++ ByteVector bv = new ByteVector(); -++ // write target_type and target_info -++ typeRef = (typeRef & 0xFF0000FF) | (lastCodeOffset << 8); -++ AnnotationWriter.putTarget(typeRef, typePath, bv); -++ // write type, and reserve space for values count -++ bv.putShort(cw.newUTF8(desc)).putShort(0); -++ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, -++ bv.length - 2); -++ if (visible) { -++ aw.next = ctanns; -++ ctanns = aw; -++ } else { -++ aw.next = ictanns; -++ ictanns = aw; -++ } -++ return aw; -++ } -++ -++ @Override -++ public void visitTryCatchBlock(final Label start, final Label end, -++ final Label handler, final String type) { -++ ++handlerCount; -++ Handler h = new Handler(); -++ h.start = start; -++ h.end = end; -++ h.handler = handler; -++ h.desc = type; -++ h.type = type != null ? cw.newClass(type) : 0; -++ if (lastHandler == null) { -++ firstHandler = h; -++ } else { -++ lastHandler.next = h; -++ } -++ lastHandler = h; -++ } -++ -++ @Override -++ public AnnotationVisitor visitTryCatchAnnotation(int typeRef, -++ TypePath typePath, String desc, boolean visible) { -++ if (!ClassReader.ANNOTATIONS) { -++ return null; -++ } -++ ByteVector bv = new ByteVector(); -++ // write target_type and target_info -++ AnnotationWriter.putTarget(typeRef, typePath, bv); -++ // write type, and reserve space for values count -++ bv.putShort(cw.newUTF8(desc)).putShort(0); -++ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, -++ bv.length - 2); -++ if (visible) { -++ aw.next = ctanns; -++ ctanns = aw; -++ } else { -++ aw.next = ictanns; -++ ictanns = aw; -++ } -++ return aw; -++ } -++ -++ @Override -++ public void visitLocalVariable(final String name, final String desc, -++ final String signature, final Label start, final Label end, -++ final int index) { -++ if (signature != null) { -++ if (localVarType == null) { -++ localVarType = new ByteVector(); -++ } -++ ++localVarTypeCount; -++ localVarType.putShort(start.position) -++ .putShort(end.position - start.position) -++ .putShort(cw.newUTF8(name)).putShort(cw.newUTF8(signature)) -++ .putShort(index); -++ } -++ if (localVar == null) { -++ localVar = new ByteVector(); -++ } -++ ++localVarCount; -++ localVar.putShort(start.position) -++ .putShort(end.position - start.position) -++ .putShort(cw.newUTF8(name)).putShort(cw.newUTF8(desc)) -++ .putShort(index); -++ if (compute != NOTHING) { -++ // updates max locals -++ char c = desc.charAt(0); -++ int n = index + (c == 'J' || c == 'D' ? 2 : 1); -++ if (n > maxLocals) { -++ maxLocals = n; -++ } -++ } -++ } -++ -++ @Override -++ public AnnotationVisitor visitLocalVariableAnnotation(int typeRef, -++ TypePath typePath, Label[] start, Label[] end, int[] index, -++ String desc, boolean visible) { -++ if (!ClassReader.ANNOTATIONS) { -++ return null; -++ } -++ ByteVector bv = new ByteVector(); -++ // write target_type and target_info -++ bv.putByte(typeRef >>> 24).putShort(start.length); -++ for (int i = 0; i < start.length; ++i) { -++ bv.putShort(start[i].position) -++ .putShort(end[i].position - start[i].position) -++ .putShort(index[i]); -++ } -++ if (typePath == null) { -++ bv.putByte(0); -++ } else { -++ int length = typePath.b[typePath.offset] * 2 + 1; -++ bv.putByteArray(typePath.b, typePath.offset, length); -++ } -++ // write type, and reserve space for values count -++ bv.putShort(cw.newUTF8(desc)).putShort(0); -++ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, -++ bv.length - 2); -++ if (visible) { -++ aw.next = ctanns; -++ ctanns = aw; -++ } else { -++ aw.next = ictanns; -++ ictanns = aw; -++ } -++ return aw; -++ } -++ -++ @Override -++ public void visitLineNumber(final int line, final Label start) { -++ if (lineNumber == null) { -++ lineNumber = new ByteVector(); -++ } -++ ++lineNumberCount; -++ lineNumber.putShort(start.position); -++ lineNumber.putShort(line); -++ } -++ -++ @Override -++ public void visitMaxs(final int maxStack, final int maxLocals) { -++ if (resize) { -++ // replaces the temporary jump opcodes introduced by Label.resolve. -++ if (ClassReader.RESIZE) { -++ resizeInstructions(); -++ } else { -++ throw new RuntimeException("Method code too large!"); -++ } -++ } -++ if (ClassReader.FRAMES && compute == FRAMES) { -++ // completes the control flow graph with exception handler blocks -++ Handler handler = firstHandler; -++ while (handler != null) { -++ Label l = handler.start.getFirst(); -++ Label h = handler.handler.getFirst(); -++ Label e = handler.end.getFirst(); -++ // computes the kind of the edges to 'h' -++ String t = handler.desc == null ? "java/lang/Throwable" -++ : handler.desc; -++ int kind = Frame.OBJECT | cw.addType(t); -++ // h is an exception handler -++ h.status |= Label.TARGET; -++ // adds 'h' as a successor of labels between 'start' and 'end' -++ while (l != e) { -++ // creates an edge to 'h' -++ Edge b = new Edge(); -++ b.info = kind; -++ b.successor = h; -++ // adds it to the successors of 'l' -++ b.next = l.successors; -++ l.successors = b; -++ // goes to the next label -++ l = l.successor; -++ } -++ handler = handler.next; -++ } -++ -++ // creates and visits the first (implicit) frame -++ Frame f = labels.frame; -++ Type[] args = Type.getArgumentTypes(descriptor); -++ f.initInputFrame(cw, access, args, this.maxLocals); -++ visitFrame(f); -++ -++ /* -++ * fix point algorithm: mark the first basic block as 'changed' -++ * (i.e. put it in the 'changed' list) and, while there are changed -++ * basic blocks, choose one, mark it as unchanged, and update its -++ * successors (which can be changed in the process). -++ */ -++ int max = 0; -++ Label changed = labels; -++ while (changed != null) { -++ // removes a basic block from the list of changed basic blocks -++ Label l = changed; -++ changed = changed.next; -++ l.next = null; -++ f = l.frame; -++ // a reachable jump target must be stored in the stack map -++ if ((l.status & Label.TARGET) != 0) { -++ l.status |= Label.STORE; -++ } -++ // all visited labels are reachable, by definition -++ l.status |= Label.REACHABLE; -++ // updates the (absolute) maximum stack size -++ int blockMax = f.inputStack.length + l.outputStackMax; -++ if (blockMax > max) { -++ max = blockMax; -++ } -++ // updates the successors of the current basic block -++ Edge e = l.successors; -++ while (e != null) { -++ Label n = e.successor.getFirst(); -++ boolean change = f.merge(cw, n.frame, e.info); -++ if (change && n.next == null) { -++ // if n has changed and is not already in the 'changed' -++ // list, adds it to this list -++ n.next = changed; -++ changed = n; -++ } -++ e = e.next; -++ } -++ } -++ -++ // visits all the frames that must be stored in the stack map -++ Label l = labels; -++ while (l != null) { -++ f = l.frame; -++ if ((l.status & Label.STORE) != 0) { -++ visitFrame(f); -++ } -++ if ((l.status & Label.REACHABLE) == 0) { -++ // finds start and end of dead basic block -++ Label k = l.successor; -++ int start = l.position; -++ int end = (k == null ? code.length : k.position) - 1; -++ // if non empty basic block -++ if (end >= start) { -++ max = Math.max(max, 1); -++ // replaces instructions with NOP ... NOP ATHROW -++ for (int i = start; i < end; ++i) { -++ code.data[i] = Opcodes.NOP; -++ } -++ code.data[end] = (byte) Opcodes.ATHROW; -++ // emits a frame for this unreachable block -++ int frameIndex = startFrame(start, 0, 1); -++ frame[frameIndex] = Frame.OBJECT -++ | cw.addType("java/lang/Throwable"); -++ endFrame(); -++ // removes the start-end range from the exception -++ // handlers -++ firstHandler = Handler.remove(firstHandler, l, k); -++ } -++ } -++ l = l.successor; -++ } -++ -++ handler = firstHandler; -++ handlerCount = 0; -++ while (handler != null) { -++ handlerCount += 1; -++ handler = handler.next; -++ } -++ -++ this.maxStack = max; -++ } else if (compute == MAXS) { -++ // completes the control flow graph with exception handler blocks -++ Handler handler = firstHandler; -++ while (handler != null) { -++ Label l = handler.start; -++ Label h = handler.handler; -++ Label e = handler.end; -++ // adds 'h' as a successor of labels between 'start' and 'end' -++ while (l != e) { -++ // creates an edge to 'h' -++ Edge b = new Edge(); -++ b.info = Edge.EXCEPTION; -++ b.successor = h; -++ // adds it to the successors of 'l' -++ if ((l.status & Label.JSR) == 0) { -++ b.next = l.successors; -++ l.successors = b; -++ } else { -++ // if l is a JSR block, adds b after the first two edges -++ // to preserve the hypothesis about JSR block successors -++ // order (see {@link #visitJumpInsn}) -++ b.next = l.successors.next.next; -++ l.successors.next.next = b; -++ } -++ // goes to the next label -++ l = l.successor; -++ } -++ handler = handler.next; -++ } -++ -++ if (subroutines > 0) { -++ // completes the control flow graph with the RET successors -++ /* -++ * first step: finds the subroutines. This step determines, for -++ * each basic block, to which subroutine(s) it belongs. -++ */ -++ // finds the basic blocks that belong to the "main" subroutine -++ int id = 0; -++ labels.visitSubroutine(null, 1, subroutines); -++ // finds the basic blocks that belong to the real subroutines -++ Label l = labels; -++ while (l != null) { -++ if ((l.status & Label.JSR) != 0) { -++ // the subroutine is defined by l's TARGET, not by l -++ Label subroutine = l.successors.next.successor; -++ // if this subroutine has not been visited yet... -++ if ((subroutine.status & Label.VISITED) == 0) { -++ // ...assigns it a new id and finds its basic blocks -++ id += 1; -++ subroutine.visitSubroutine(null, (id / 32L) << 32 -++ | (1L << (id % 32)), subroutines); -++ } -++ } -++ l = l.successor; -++ } -++ // second step: finds the successors of RET blocks -++ l = labels; -++ while (l != null) { -++ if ((l.status & Label.JSR) != 0) { -++ Label L = labels; -++ while (L != null) { -++ L.status &= ~Label.VISITED2; -++ L = L.successor; -++ } -++ // the subroutine is defined by l's TARGET, not by l -++ Label subroutine = l.successors.next.successor; -++ subroutine.visitSubroutine(l, 0, subroutines); -++ } -++ l = l.successor; -++ } -++ } -++ -++ /* -++ * control flow analysis algorithm: while the block stack is not -++ * empty, pop a block from this stack, update the max stack size, -++ * compute the true (non relative) begin stack size of the -++ * successors of this block, and push these successors onto the -++ * stack (unless they have already been pushed onto the stack). -++ * Note: by hypothesis, the {@link Label#inputStackTop} of the -++ * blocks in the block stack are the true (non relative) beginning -++ * stack sizes of these blocks. -++ */ -++ int max = 0; -++ Label stack = labels; -++ while (stack != null) { -++ // pops a block from the stack -++ Label l = stack; -++ stack = stack.next; -++ // computes the true (non relative) max stack size of this block -++ int start = l.inputStackTop; -++ int blockMax = start + l.outputStackMax; -++ // updates the global max stack size -++ if (blockMax > max) { -++ max = blockMax; -++ } -++ // analyzes the successors of the block -++ Edge b = l.successors; -++ if ((l.status & Label.JSR) != 0) { -++ // ignores the first edge of JSR blocks (virtual successor) -++ b = b.next; -++ } -++ while (b != null) { -++ l = b.successor; -++ // if this successor has not already been pushed... -++ if ((l.status & Label.PUSHED) == 0) { -++ // computes its true beginning stack size... -++ l.inputStackTop = b.info == Edge.EXCEPTION ? 1 : start -++ + b.info; -++ // ...and pushes it onto the stack -++ l.status |= Label.PUSHED; -++ l.next = stack; -++ stack = l; -++ } -++ b = b.next; -++ } -++ } -++ this.maxStack = Math.max(maxStack, max); -++ } else { -++ this.maxStack = maxStack; -++ this.maxLocals = maxLocals; -++ } -++ } -++ -++ @Override -++ public void visitEnd() { -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Utility methods: control flow analysis algorithm -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Adds a successor to the {@link #currentBlock currentBlock} block. -++ * -++ * @param info -++ * information about the control flow edge to be added. -++ * @param successor -++ * the successor block to be added to the current block. -++ */ -++ private void addSuccessor(final int info, final Label successor) { -++ // creates and initializes an Edge object... -++ Edge b = new Edge(); -++ b.info = info; -++ b.successor = successor; -++ // ...and adds it to the successor list of the currentBlock block -++ b.next = currentBlock.successors; -++ currentBlock.successors = b; -++ } -++ -++ /** -++ * Ends the current basic block. This method must be used in the case where -++ * the current basic block does not have any successor. -++ */ -++ private void noSuccessor() { -++ if (compute == FRAMES) { -++ Label l = new Label(); -++ l.frame = new Frame(); -++ l.frame.owner = l; -++ l.resolve(this, code.length, code.data); -++ previousBlock.successor = l; -++ previousBlock = l; -++ } else { -++ currentBlock.outputStackMax = maxStackSize; -++ } -++ currentBlock = null; -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Utility methods: stack map frames -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Visits a frame that has been computed from scratch. -++ * -++ * @param f -++ * the frame that must be visited. -++ */ -++ private void visitFrame(final Frame f) { -++ int i, t; -++ int nTop = 0; -++ int nLocal = 0; -++ int nStack = 0; -++ int[] locals = f.inputLocals; -++ int[] stacks = f.inputStack; -++ // computes the number of locals (ignores TOP types that are just after -++ // a LONG or a DOUBLE, and all trailing TOP types) -++ for (i = 0; i < locals.length; ++i) { -++ t = locals[i]; -++ if (t == Frame.TOP) { -++ ++nTop; -++ } else { -++ nLocal += nTop + 1; -++ nTop = 0; -++ } -++ if (t == Frame.LONG || t == Frame.DOUBLE) { -++ ++i; -++ } -++ } -++ // computes the stack size (ignores TOP types that are just after -++ // a LONG or a DOUBLE) -++ for (i = 0; i < stacks.length; ++i) { -++ t = stacks[i]; -++ ++nStack; -++ if (t == Frame.LONG || t == Frame.DOUBLE) { -++ ++i; -++ } -++ } -++ // visits the frame and its content -++ int frameIndex = startFrame(f.owner.position, nLocal, nStack); -++ for (i = 0; nLocal > 0; ++i, --nLocal) { -++ t = locals[i]; -++ frame[frameIndex++] = t; -++ if (t == Frame.LONG || t == Frame.DOUBLE) { -++ ++i; -++ } -++ } -++ for (i = 0; i < stacks.length; ++i) { -++ t = stacks[i]; -++ frame[frameIndex++] = t; -++ if (t == Frame.LONG || t == Frame.DOUBLE) { -++ ++i; -++ } -++ } -++ endFrame(); -++ } -++ -++ /** -++ * Visit the implicit first frame of this method. -++ */ -++ private void visitImplicitFirstFrame() { -++ // There can be at most descriptor.length() + 1 locals -++ int frameIndex = startFrame(0, descriptor.length() + 1, 0); -++ if ((access & Opcodes.ACC_STATIC) == 0) { -++ if ((access & ACC_CONSTRUCTOR) == 0) { -++ frame[frameIndex++] = Frame.OBJECT | cw.addType(cw.thisName); -++ } else { -++ frame[frameIndex++] = 6; // Opcodes.UNINITIALIZED_THIS; -++ } -++ } -++ int i = 1; -++ loop: while (true) { -++ int j = i; -++ switch (descriptor.charAt(i++)) { -++ case 'Z': -++ case 'C': -++ case 'B': -++ case 'S': -++ case 'I': -++ frame[frameIndex++] = 1; // Opcodes.INTEGER; -++ break; -++ case 'F': -++ frame[frameIndex++] = 2; // Opcodes.FLOAT; -++ break; -++ case 'J': -++ frame[frameIndex++] = 4; // Opcodes.LONG; -++ break; -++ case 'D': -++ frame[frameIndex++] = 3; // Opcodes.DOUBLE; -++ break; -++ case '[': -++ while (descriptor.charAt(i) == '[') { -++ ++i; -++ } -++ if (descriptor.charAt(i) == 'L') { -++ ++i; -++ while (descriptor.charAt(i) != ';') { -++ ++i; -++ } -++ } -++ frame[frameIndex++] = Frame.OBJECT -++ | cw.addType(descriptor.substring(j, ++i)); -++ break; -++ case 'L': -++ while (descriptor.charAt(i) != ';') { -++ ++i; -++ } -++ frame[frameIndex++] = Frame.OBJECT -++ | cw.addType(descriptor.substring(j + 1, i++)); -++ break; -++ default: -++ break loop; -++ } -++ } -++ frame[1] = frameIndex - 3; -++ endFrame(); -++ } -++ -++ /** -++ * Starts the visit of a stack map frame. -++ * -++ * @param offset -++ * the offset of the instruction to which the frame corresponds. -++ * @param nLocal -++ * the number of local variables in the frame. -++ * @param nStack -++ * the number of stack elements in the frame. -++ * @return the index of the next element to be written in this frame. -++ */ -++ private int startFrame(final int offset, final int nLocal, final int nStack) { -++ int n = 3 + nLocal + nStack; -++ if (frame == null || frame.length < n) { -++ frame = new int[n]; -++ } -++ frame[0] = offset; -++ frame[1] = nLocal; -++ frame[2] = nStack; -++ return 3; -++ } -++ -++ /** -++ * Checks if the visit of the current frame {@link #frame} is finished, and -++ * if yes, write it in the StackMapTable attribute. -++ */ -++ private void endFrame() { -++ if (previousFrame != null) { // do not write the first frame -++ if (stackMap == null) { -++ stackMap = new ByteVector(); -++ } -++ writeFrame(); -++ ++frameCount; -++ } -++ previousFrame = frame; -++ frame = null; -++ } -++ -++ /** -++ * Compress and writes the current frame {@link #frame} in the StackMapTable -++ * attribute. -++ */ -++ private void writeFrame() { -++ int clocalsSize = frame[1]; -++ int cstackSize = frame[2]; -++ if ((cw.version & 0xFFFF) < Opcodes.V1_6) { -++ stackMap.putShort(frame[0]).putShort(clocalsSize); -++ writeFrameTypes(3, 3 + clocalsSize); -++ stackMap.putShort(cstackSize); -++ writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize); -++ return; -++ } -++ int localsSize = previousFrame[1]; -++ int type = FULL_FRAME; -++ int k = 0; -++ int delta; -++ if (frameCount == 0) { -++ delta = frame[0]; -++ } else { -++ delta = frame[0] - previousFrame[0] - 1; -++ } -++ if (cstackSize == 0) { -++ k = clocalsSize - localsSize; -++ switch (k) { -++ case -3: -++ case -2: -++ case -1: -++ type = CHOP_FRAME; -++ localsSize = clocalsSize; -++ break; -++ case 0: -++ type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED; -++ break; -++ case 1: -++ case 2: -++ case 3: -++ type = APPEND_FRAME; -++ break; -++ } -++ } else if (clocalsSize == localsSize && cstackSize == 1) { -++ type = delta < 63 ? SAME_LOCALS_1_STACK_ITEM_FRAME -++ : SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED; -++ } -++ if (type != FULL_FRAME) { -++ // verify if locals are the same -++ int l = 3; -++ for (int j = 0; j < localsSize; j++) { -++ if (frame[l] != previousFrame[l]) { -++ type = FULL_FRAME; -++ break; -++ } -++ l++; -++ } -++ } -++ switch (type) { -++ case SAME_FRAME: -++ stackMap.putByte(delta); -++ break; -++ case SAME_LOCALS_1_STACK_ITEM_FRAME: -++ stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); -++ writeFrameTypes(3 + clocalsSize, 4 + clocalsSize); -++ break; -++ case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED: -++ stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED).putShort( -++ delta); -++ writeFrameTypes(3 + clocalsSize, 4 + clocalsSize); -++ break; -++ case SAME_FRAME_EXTENDED: -++ stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta); -++ break; -++ case CHOP_FRAME: -++ stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta); -++ break; -++ case APPEND_FRAME: -++ stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta); -++ writeFrameTypes(3 + localsSize, 3 + clocalsSize); -++ break; -++ // case FULL_FRAME: -++ default: -++ stackMap.putByte(FULL_FRAME).putShort(delta).putShort(clocalsSize); -++ writeFrameTypes(3, 3 + clocalsSize); -++ stackMap.putShort(cstackSize); -++ writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize); -++ } -++ } -++ -++ /** -++ * Writes some types of the current frame {@link #frame} into the -++ * StackMapTableAttribute. This method converts types from the format used -++ * in {@link Label} to the format used in StackMapTable attributes. In -++ * particular, it converts type table indexes to constant pool indexes. -++ * -++ * @param start -++ * index of the first type in {@link #frame} to write. -++ * @param end -++ * index of last type in {@link #frame} to write (exclusive). -++ */ -++ private void writeFrameTypes(final int start, final int end) { -++ for (int i = start; i < end; ++i) { -++ int t = frame[i]; -++ int d = t & Frame.DIM; -++ if (d == 0) { -++ int v = t & Frame.BASE_VALUE; -++ switch (t & Frame.BASE_KIND) { -++ case Frame.OBJECT: -++ stackMap.putByte(7).putShort( -++ cw.newClass(cw.typeTable[v].strVal1)); -++ break; -++ case Frame.UNINITIALIZED: -++ stackMap.putByte(8).putShort(cw.typeTable[v].intVal); -++ break; -++ default: -++ stackMap.putByte(v); -++ } -++ } else { -++ StringBuilder sb = new StringBuilder(); -++ d >>= 28; -++ while (d-- > 0) { -++ sb.append('['); -++ } -++ if ((t & Frame.BASE_KIND) == Frame.OBJECT) { -++ sb.append('L'); -++ sb.append(cw.typeTable[t & Frame.BASE_VALUE].strVal1); -++ sb.append(';'); -++ } else { -++ switch (t & 0xF) { -++ case 1: -++ sb.append('I'); -++ break; -++ case 2: -++ sb.append('F'); -++ break; -++ case 3: -++ sb.append('D'); -++ break; -++ case 9: -++ sb.append('Z'); -++ break; -++ case 10: -++ sb.append('B'); -++ break; -++ case 11: -++ sb.append('C'); -++ break; -++ case 12: -++ sb.append('S'); -++ break; -++ default: -++ sb.append('J'); -++ } -++ } -++ stackMap.putByte(7).putShort(cw.newClass(sb.toString())); -++ } -++ } -++ } -++ -++ private void writeFrameType(final Object type) { -++ if (type instanceof String) { -++ stackMap.putByte(7).putShort(cw.newClass((String) type)); -++ } else if (type instanceof Integer) { -++ stackMap.putByte(((Integer) type).intValue()); -++ } else { -++ stackMap.putByte(8).putShort(((Label) type).position); -++ } -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Utility methods: dump bytecode array -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Returns the size of the bytecode of this method. -++ * -++ * @return the size of the bytecode of this method. -++ */ -++ final int getSize() { -++ if (classReaderOffset != 0) { -++ return 6 + classReaderLength; -++ } -++ int size = 8; -++ if (code.length > 0) { -++ if (code.length > 65536) { -++ throw new RuntimeException("Method code too large!"); -++ } -++ cw.newUTF8("Code"); -++ size += 18 + code.length + 8 * handlerCount; -++ if (localVar != null) { -++ cw.newUTF8("LocalVariableTable"); -++ size += 8 + localVar.length; -++ } -++ if (localVarType != null) { -++ cw.newUTF8("LocalVariableTypeTable"); -++ size += 8 + localVarType.length; -++ } -++ if (lineNumber != null) { -++ cw.newUTF8("LineNumberTable"); -++ size += 8 + lineNumber.length; -++ } -++ if (stackMap != null) { -++ boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6; -++ cw.newUTF8(zip ? "StackMapTable" : "StackMap"); -++ size += 8 + stackMap.length; -++ } -++ if (ClassReader.ANNOTATIONS && ctanns != null) { -++ cw.newUTF8("RuntimeVisibleTypeAnnotations"); -++ size += 8 + ctanns.getSize(); -++ } -++ if (ClassReader.ANNOTATIONS && ictanns != null) { -++ cw.newUTF8("RuntimeInvisibleTypeAnnotations"); -++ size += 8 + ictanns.getSize(); -++ } -++ if (cattrs != null) { -++ size += cattrs.getSize(cw, code.data, code.length, maxStack, -++ maxLocals); -++ } -++ } -++ if (exceptionCount > 0) { -++ cw.newUTF8("Exceptions"); -++ size += 8 + 2 * exceptionCount; -++ } -++ if ((access & Opcodes.ACC_SYNTHETIC) != 0) { -++ if ((cw.version & 0xFFFF) < Opcodes.V1_5 -++ || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { -++ cw.newUTF8("Synthetic"); -++ size += 6; -++ } -++ } -++ if ((access & Opcodes.ACC_DEPRECATED) != 0) { -++ cw.newUTF8("Deprecated"); -++ size += 6; -++ } -++ if (ClassReader.SIGNATURES && signature != null) { -++ cw.newUTF8("Signature"); -++ cw.newUTF8(signature); -++ size += 8; -++ } -++ if (methodParameters != null) { -++ cw.newUTF8("MethodParameters"); -++ size += 7 + methodParameters.length; -++ } -++ if (ClassReader.ANNOTATIONS && annd != null) { -++ cw.newUTF8("AnnotationDefault"); -++ size += 6 + annd.length; -++ } -++ if (ClassReader.ANNOTATIONS && anns != null) { -++ cw.newUTF8("RuntimeVisibleAnnotations"); -++ size += 8 + anns.getSize(); -++ } -++ if (ClassReader.ANNOTATIONS && ianns != null) { -++ cw.newUTF8("RuntimeInvisibleAnnotations"); -++ size += 8 + ianns.getSize(); -++ } -++ if (ClassReader.ANNOTATIONS && tanns != null) { -++ cw.newUTF8("RuntimeVisibleTypeAnnotations"); -++ size += 8 + tanns.getSize(); -++ } -++ if (ClassReader.ANNOTATIONS && itanns != null) { -++ cw.newUTF8("RuntimeInvisibleTypeAnnotations"); -++ size += 8 + itanns.getSize(); -++ } -++ if (ClassReader.ANNOTATIONS && panns != null) { -++ cw.newUTF8("RuntimeVisibleParameterAnnotations"); -++ size += 7 + 2 * (panns.length - synthetics); -++ for (int i = panns.length - 1; i >= synthetics; --i) { -++ size += panns[i] == null ? 0 : panns[i].getSize(); -++ } -++ } -++ if (ClassReader.ANNOTATIONS && ipanns != null) { -++ cw.newUTF8("RuntimeInvisibleParameterAnnotations"); -++ size += 7 + 2 * (ipanns.length - synthetics); -++ for (int i = ipanns.length - 1; i >= synthetics; --i) { -++ size += ipanns[i] == null ? 0 : ipanns[i].getSize(); -++ } -++ } -++ if (attrs != null) { -++ size += attrs.getSize(cw, null, 0, -1, -1); -++ } -++ return size; -++ } -++ -++ /** -++ * Puts the bytecode of this method in the given byte vector. -++ * -++ * @param out -++ * the byte vector into which the bytecode of this method must be -++ * copied. -++ */ -++ final void put(final ByteVector out) { -++ final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC; -++ int mask = ACC_CONSTRUCTOR | Opcodes.ACC_DEPRECATED -++ | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE -++ | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR); -++ out.putShort(access & ~mask).putShort(name).putShort(desc); -++ if (classReaderOffset != 0) { -++ out.putByteArray(cw.cr.b, classReaderOffset, classReaderLength); -++ return; -++ } -++ int attributeCount = 0; -++ if (code.length > 0) { -++ ++attributeCount; -++ } -++ if (exceptionCount > 0) { -++ ++attributeCount; -++ } -++ if ((access & Opcodes.ACC_SYNTHETIC) != 0) { -++ if ((cw.version & 0xFFFF) < Opcodes.V1_5 -++ || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { -++ ++attributeCount; -++ } -++ } -++ if ((access & Opcodes.ACC_DEPRECATED) != 0) { -++ ++attributeCount; -++ } -++ if (ClassReader.SIGNATURES && signature != null) { -++ ++attributeCount; -++ } -++ if (methodParameters != null) { -++ ++attributeCount; -++ } -++ if (ClassReader.ANNOTATIONS && annd != null) { -++ ++attributeCount; -++ } -++ if (ClassReader.ANNOTATIONS && anns != null) { -++ ++attributeCount; -++ } -++ if (ClassReader.ANNOTATIONS && ianns != null) { -++ ++attributeCount; -++ } -++ if (ClassReader.ANNOTATIONS && tanns != null) { -++ ++attributeCount; -++ } -++ if (ClassReader.ANNOTATIONS && itanns != null) { -++ ++attributeCount; -++ } -++ if (ClassReader.ANNOTATIONS && panns != null) { -++ ++attributeCount; -++ } -++ if (ClassReader.ANNOTATIONS && ipanns != null) { -++ ++attributeCount; -++ } -++ if (attrs != null) { -++ attributeCount += attrs.getCount(); -++ } -++ out.putShort(attributeCount); -++ if (code.length > 0) { -++ int size = 12 + code.length + 8 * handlerCount; -++ if (localVar != null) { -++ size += 8 + localVar.length; -++ } -++ if (localVarType != null) { -++ size += 8 + localVarType.length; -++ } -++ if (lineNumber != null) { -++ size += 8 + lineNumber.length; -++ } -++ if (stackMap != null) { -++ size += 8 + stackMap.length; -++ } -++ if (ClassReader.ANNOTATIONS && ctanns != null) { -++ size += 8 + ctanns.getSize(); -++ } -++ if (ClassReader.ANNOTATIONS && ictanns != null) { -++ size += 8 + ictanns.getSize(); -++ } -++ if (cattrs != null) { -++ size += cattrs.getSize(cw, code.data, code.length, maxStack, -++ maxLocals); -++ } -++ out.putShort(cw.newUTF8("Code")).putInt(size); -++ out.putShort(maxStack).putShort(maxLocals); -++ out.putInt(code.length).putByteArray(code.data, 0, code.length); -++ out.putShort(handlerCount); -++ if (handlerCount > 0) { -++ Handler h = firstHandler; -++ while (h != null) { -++ out.putShort(h.start.position).putShort(h.end.position) -++ .putShort(h.handler.position).putShort(h.type); -++ h = h.next; -++ } -++ } -++ attributeCount = 0; -++ if (localVar != null) { -++ ++attributeCount; -++ } -++ if (localVarType != null) { -++ ++attributeCount; -++ } -++ if (lineNumber != null) { -++ ++attributeCount; -++ } -++ if (stackMap != null) { -++ ++attributeCount; -++ } -++ if (ClassReader.ANNOTATIONS && ctanns != null) { -++ ++attributeCount; -++ } -++ if (ClassReader.ANNOTATIONS && ictanns != null) { -++ ++attributeCount; -++ } -++ if (cattrs != null) { -++ attributeCount += cattrs.getCount(); -++ } -++ out.putShort(attributeCount); -++ if (localVar != null) { -++ out.putShort(cw.newUTF8("LocalVariableTable")); -++ out.putInt(localVar.length + 2).putShort(localVarCount); -++ out.putByteArray(localVar.data, 0, localVar.length); -++ } -++ if (localVarType != null) { -++ out.putShort(cw.newUTF8("LocalVariableTypeTable")); -++ out.putInt(localVarType.length + 2).putShort(localVarTypeCount); -++ out.putByteArray(localVarType.data, 0, localVarType.length); -++ } -++ if (lineNumber != null) { -++ out.putShort(cw.newUTF8("LineNumberTable")); -++ out.putInt(lineNumber.length + 2).putShort(lineNumberCount); -++ out.putByteArray(lineNumber.data, 0, lineNumber.length); -++ } -++ if (stackMap != null) { -++ boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6; -++ out.putShort(cw.newUTF8(zip ? "StackMapTable" : "StackMap")); -++ out.putInt(stackMap.length + 2).putShort(frameCount); -++ out.putByteArray(stackMap.data, 0, stackMap.length); -++ } -++ if (ClassReader.ANNOTATIONS && ctanns != null) { -++ out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations")); -++ ctanns.put(out); -++ } -++ if (ClassReader.ANNOTATIONS && ictanns != null) { -++ out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations")); -++ ictanns.put(out); -++ } -++ if (cattrs != null) { -++ cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out); -++ } -++ } -++ if (exceptionCount > 0) { -++ out.putShort(cw.newUTF8("Exceptions")).putInt( -++ 2 * exceptionCount + 2); -++ out.putShort(exceptionCount); -++ for (int i = 0; i < exceptionCount; ++i) { -++ out.putShort(exceptions[i]); -++ } -++ } -++ if ((access & Opcodes.ACC_SYNTHETIC) != 0) { -++ if ((cw.version & 0xFFFF) < Opcodes.V1_5 -++ || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { -++ out.putShort(cw.newUTF8("Synthetic")).putInt(0); -++ } -++ } -++ if ((access & Opcodes.ACC_DEPRECATED) != 0) { -++ out.putShort(cw.newUTF8("Deprecated")).putInt(0); -++ } -++ if (ClassReader.SIGNATURES && signature != null) { -++ out.putShort(cw.newUTF8("Signature")).putInt(2) -++ .putShort(cw.newUTF8(signature)); -++ } -++ if (methodParameters != null) { -++ out.putShort(cw.newUTF8("MethodParameters")); -++ out.putInt(methodParameters.length + 1).putByte( -++ methodParametersCount); -++ out.putByteArray(methodParameters.data, 0, methodParameters.length); -++ } -++ if (ClassReader.ANNOTATIONS && annd != null) { -++ out.putShort(cw.newUTF8("AnnotationDefault")); -++ out.putInt(annd.length); -++ out.putByteArray(annd.data, 0, annd.length); -++ } -++ if (ClassReader.ANNOTATIONS && anns != null) { -++ out.putShort(cw.newUTF8("RuntimeVisibleAnnotations")); -++ anns.put(out); -++ } -++ if (ClassReader.ANNOTATIONS && ianns != null) { -++ out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations")); -++ ianns.put(out); -++ } -++ if (ClassReader.ANNOTATIONS && tanns != null) { -++ out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations")); -++ tanns.put(out); -++ } -++ if (ClassReader.ANNOTATIONS && itanns != null) { -++ out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations")); -++ itanns.put(out); -++ } -++ if (ClassReader.ANNOTATIONS && panns != null) { -++ out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations")); -++ AnnotationWriter.put(panns, synthetics, out); -++ } -++ if (ClassReader.ANNOTATIONS && ipanns != null) { -++ out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations")); -++ AnnotationWriter.put(ipanns, synthetics, out); -++ } -++ if (attrs != null) { -++ attrs.put(cw, null, 0, -1, -1, out); -++ } -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Utility methods: instruction resizing (used to handle GOTO_W and JSR_W) -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Resizes and replaces the temporary instructions inserted by -++ * {@link Label#resolve} for wide forward jumps, while keeping jump offsets -++ * and instruction addresses consistent. This may require to resize other -++ * existing instructions, or even to introduce new instructions: for -++ * example, increasing the size of an instruction by 2 at the middle of a -++ * method can increases the offset of an IFEQ instruction from 32766 to -++ * 32768, in which case IFEQ 32766 must be replaced with IFNEQ 8 GOTO_W -++ * 32765. This, in turn, may require to increase the size of another jump -++ * instruction, and so on... All these operations are handled automatically -++ * by this method. -++ *

-++ * This method must be called after all the method that is being built -++ * has been visited. In particular, the {@link Label Label} objects used -++ * to construct the method are no longer valid after this method has been -++ * called. -++ */ -++ private void resizeInstructions() { -++ byte[] b = code.data; // bytecode of the method -++ int u, v, label; // indexes in b -++ int i, j; // loop indexes -++ /* -++ * 1st step: As explained above, resizing an instruction may require to -++ * resize another one, which may require to resize yet another one, and -++ * so on. The first step of the algorithm consists in finding all the -++ * instructions that need to be resized, without modifying the code. -++ * This is done by the following "fix point" algorithm: -++ * -++ * Parse the code to find the jump instructions whose offset will need -++ * more than 2 bytes to be stored (the future offset is computed from -++ * the current offset and from the number of bytes that will be inserted -++ * or removed between the source and target instructions). For each such -++ * instruction, adds an entry in (a copy of) the indexes and sizes -++ * arrays (if this has not already been done in a previous iteration!). -++ * -++ * If at least one entry has been added during the previous step, go -++ * back to the beginning, otherwise stop. -++ * -++ * In fact the real algorithm is complicated by the fact that the size -++ * of TABLESWITCH and LOOKUPSWITCH instructions depends on their -++ * position in the bytecode (because of padding). In order to ensure the -++ * convergence of the algorithm, the number of bytes to be added or -++ * removed from these instructions is over estimated during the previous -++ * loop, and computed exactly only after the loop is finished (this -++ * requires another pass to parse the bytecode of the method). -++ */ -++ int[] allIndexes = new int[0]; // copy of indexes -++ int[] allSizes = new int[0]; // copy of sizes -++ boolean[] resize; // instructions to be resized -++ int newOffset; // future offset of a jump instruction -++ -++ resize = new boolean[code.length]; -++ -++ // 3 = loop again, 2 = loop ended, 1 = last pass, 0 = done -++ int state = 3; -++ do { -++ if (state == 3) { -++ state = 2; -++ } -++ u = 0; -++ while (u < b.length) { -++ int opcode = b[u] & 0xFF; // opcode of current instruction -++ int insert = 0; // bytes to be added after this instruction -++ -++ switch (ClassWriter.TYPE[opcode]) { -++ case ClassWriter.NOARG_INSN: -++ case ClassWriter.IMPLVAR_INSN: -++ u += 1; -++ break; -++ case ClassWriter.LABEL_INSN: -++ if (opcode > 201) { -++ // converts temporary opcodes 202 to 217, 218 and -++ // 219 to IFEQ ... JSR (inclusive), IFNULL and -++ // IFNONNULL -++ opcode = opcode < 218 ? opcode - 49 : opcode - 20; -++ label = u + readUnsignedShort(b, u + 1); -++ } else { -++ label = u + readShort(b, u + 1); -++ } -++ newOffset = getNewOffset(allIndexes, allSizes, u, label); -++ if (newOffset < Short.MIN_VALUE -++ || newOffset > Short.MAX_VALUE) { -++ if (!resize[u]) { -++ if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) { -++ // two additional bytes will be required to -++ // replace this GOTO or JSR instruction with -++ // a GOTO_W or a JSR_W -++ insert = 2; -++ } else { -++ // five additional bytes will be required to -++ // replace this IFxxx instruction with -++ // IFNOTxxx GOTO_W , where IFNOTxxx -++ // is the "opposite" opcode of IFxxx (i.e., -++ // IFNE for IFEQ) and where designates -++ // the instruction just after the GOTO_W. -++ insert = 5; -++ } -++ resize[u] = true; -++ } -++ } -++ u += 3; -++ break; -++ case ClassWriter.LABELW_INSN: -++ u += 5; -++ break; -++ case ClassWriter.TABL_INSN: -++ if (state == 1) { -++ // true number of bytes to be added (or removed) -++ // from this instruction = (future number of padding -++ // bytes - current number of padding byte) - -++ // previously over estimated variation = -++ // = ((3 - newOffset%4) - (3 - u%4)) - u%4 -++ // = (-newOffset%4 + u%4) - u%4 -++ // = -(newOffset & 3) -++ newOffset = getNewOffset(allIndexes, allSizes, 0, u); -++ insert = -(newOffset & 3); -++ } else if (!resize[u]) { -++ // over estimation of the number of bytes to be -++ // added to this instruction = 3 - current number -++ // of padding bytes = 3 - (3 - u%4) = u%4 = u & 3 -++ insert = u & 3; -++ resize[u] = true; -++ } -++ // skips instruction -++ u = u + 4 - (u & 3); -++ u += 4 * (readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12; -++ break; -++ case ClassWriter.LOOK_INSN: -++ if (state == 1) { -++ // like TABL_INSN -++ newOffset = getNewOffset(allIndexes, allSizes, 0, u); -++ insert = -(newOffset & 3); -++ } else if (!resize[u]) { -++ // like TABL_INSN -++ insert = u & 3; -++ resize[u] = true; -++ } -++ // skips instruction -++ u = u + 4 - (u & 3); -++ u += 8 * readInt(b, u + 4) + 8; -++ break; -++ case ClassWriter.WIDE_INSN: -++ opcode = b[u + 1] & 0xFF; -++ if (opcode == Opcodes.IINC) { -++ u += 6; -++ } else { -++ u += 4; -++ } -++ break; -++ case ClassWriter.VAR_INSN: -++ case ClassWriter.SBYTE_INSN: -++ case ClassWriter.LDC_INSN: -++ u += 2; -++ break; -++ case ClassWriter.SHORT_INSN: -++ case ClassWriter.LDCW_INSN: -++ case ClassWriter.FIELDORMETH_INSN: -++ case ClassWriter.TYPE_INSN: -++ case ClassWriter.IINC_INSN: -++ u += 3; -++ break; -++ case ClassWriter.ITFMETH_INSN: -++ case ClassWriter.INDYMETH_INSN: -++ u += 5; -++ break; -++ // case ClassWriter.MANA_INSN: -++ default: -++ u += 4; -++ break; -++ } -++ if (insert != 0) { -++ // adds a new (u, insert) entry in the allIndexes and -++ // allSizes arrays -++ int[] newIndexes = new int[allIndexes.length + 1]; -++ int[] newSizes = new int[allSizes.length + 1]; -++ System.arraycopy(allIndexes, 0, newIndexes, 0, -++ allIndexes.length); -++ System.arraycopy(allSizes, 0, newSizes, 0, allSizes.length); -++ newIndexes[allIndexes.length] = u; -++ newSizes[allSizes.length] = insert; -++ allIndexes = newIndexes; -++ allSizes = newSizes; -++ if (insert > 0) { -++ state = 3; -++ } -++ } -++ } -++ if (state < 3) { -++ --state; -++ } -++ } while (state != 0); -++ -++ // 2nd step: -++ // copies the bytecode of the method into a new bytevector, updates the -++ // offsets, and inserts (or removes) bytes as requested. -++ -++ ByteVector newCode = new ByteVector(code.length); -++ -++ u = 0; -++ while (u < code.length) { -++ int opcode = b[u] & 0xFF; -++ switch (ClassWriter.TYPE[opcode]) { -++ case ClassWriter.NOARG_INSN: -++ case ClassWriter.IMPLVAR_INSN: -++ newCode.putByte(opcode); -++ u += 1; -++ break; -++ case ClassWriter.LABEL_INSN: -++ if (opcode > 201) { -++ // changes temporary opcodes 202 to 217 (inclusive), 218 -++ // and 219 to IFEQ ... JSR (inclusive), IFNULL and -++ // IFNONNULL -++ opcode = opcode < 218 ? opcode - 49 : opcode - 20; -++ label = u + readUnsignedShort(b, u + 1); -++ } else { -++ label = u + readShort(b, u + 1); -++ } -++ newOffset = getNewOffset(allIndexes, allSizes, u, label); -++ if (resize[u]) { -++ // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx -++ // with IFNOTxxx GOTO_W , where IFNOTxxx is -++ // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) -++ // and where designates the instruction just after -++ // the GOTO_W. -++ if (opcode == Opcodes.GOTO) { -++ newCode.putByte(200); // GOTO_W -++ } else if (opcode == Opcodes.JSR) { -++ newCode.putByte(201); // JSR_W -++ } else { -++ newCode.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 -++ : opcode ^ 1); -++ newCode.putShort(8); // jump offset -++ newCode.putByte(200); // GOTO_W -++ // newOffset now computed from start of GOTO_W -++ newOffset -= 3; -++ } -++ newCode.putInt(newOffset); -++ } else { -++ newCode.putByte(opcode); -++ newCode.putShort(newOffset); -++ } -++ u += 3; -++ break; -++ case ClassWriter.LABELW_INSN: -++ label = u + readInt(b, u + 1); -++ newOffset = getNewOffset(allIndexes, allSizes, u, label); -++ newCode.putByte(opcode); -++ newCode.putInt(newOffset); -++ u += 5; -++ break; -++ case ClassWriter.TABL_INSN: -++ // skips 0 to 3 padding bytes -++ v = u; -++ u = u + 4 - (v & 3); -++ // reads and copies instruction -++ newCode.putByte(Opcodes.TABLESWITCH); -++ newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4); -++ label = v + readInt(b, u); -++ u += 4; -++ newOffset = getNewOffset(allIndexes, allSizes, v, label); -++ newCode.putInt(newOffset); -++ j = readInt(b, u); -++ u += 4; -++ newCode.putInt(j); -++ j = readInt(b, u) - j + 1; -++ u += 4; -++ newCode.putInt(readInt(b, u - 4)); -++ for (; j > 0; --j) { -++ label = v + readInt(b, u); -++ u += 4; -++ newOffset = getNewOffset(allIndexes, allSizes, v, label); -++ newCode.putInt(newOffset); -++ } -++ break; -++ case ClassWriter.LOOK_INSN: -++ // skips 0 to 3 padding bytes -++ v = u; -++ u = u + 4 - (v & 3); -++ // reads and copies instruction -++ newCode.putByte(Opcodes.LOOKUPSWITCH); -++ newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4); -++ label = v + readInt(b, u); -++ u += 4; -++ newOffset = getNewOffset(allIndexes, allSizes, v, label); -++ newCode.putInt(newOffset); -++ j = readInt(b, u); -++ u += 4; -++ newCode.putInt(j); -++ for (; j > 0; --j) { -++ newCode.putInt(readInt(b, u)); -++ u += 4; -++ label = v + readInt(b, u); -++ u += 4; -++ newOffset = getNewOffset(allIndexes, allSizes, v, label); -++ newCode.putInt(newOffset); -++ } -++ break; -++ case ClassWriter.WIDE_INSN: -++ opcode = b[u + 1] & 0xFF; -++ if (opcode == Opcodes.IINC) { -++ newCode.putByteArray(b, u, 6); -++ u += 6; -++ } else { -++ newCode.putByteArray(b, u, 4); -++ u += 4; -++ } -++ break; -++ case ClassWriter.VAR_INSN: -++ case ClassWriter.SBYTE_INSN: -++ case ClassWriter.LDC_INSN: -++ newCode.putByteArray(b, u, 2); -++ u += 2; -++ break; -++ case ClassWriter.SHORT_INSN: -++ case ClassWriter.LDCW_INSN: -++ case ClassWriter.FIELDORMETH_INSN: -++ case ClassWriter.TYPE_INSN: -++ case ClassWriter.IINC_INSN: -++ newCode.putByteArray(b, u, 3); -++ u += 3; -++ break; -++ case ClassWriter.ITFMETH_INSN: -++ case ClassWriter.INDYMETH_INSN: -++ newCode.putByteArray(b, u, 5); -++ u += 5; -++ break; -++ // case MANA_INSN: -++ default: -++ newCode.putByteArray(b, u, 4); -++ u += 4; -++ break; -++ } -++ } -++ -++ // updates the stack map frame labels -++ if (compute == FRAMES) { -++ Label l = labels; -++ while (l != null) { -++ /* -++ * Detects the labels that are just after an IF instruction that -++ * has been resized with the IFNOT GOTO_W pattern. These labels -++ * are now the target of a jump instruction (the IFNOT -++ * instruction). Note that we need the original label position -++ * here. getNewOffset must therefore never have been called for -++ * this label. -++ */ -++ u = l.position - 3; -++ if (u >= 0 && resize[u]) { -++ l.status |= Label.TARGET; -++ } -++ getNewOffset(allIndexes, allSizes, l); -++ l = l.successor; -++ } -++ // Update the offsets in the uninitialized types -++ if (cw.typeTable != null) { -++ for (i = 0; i < cw.typeTable.length; ++i) { -++ Item item = cw.typeTable[i]; -++ if (item != null && item.type == ClassWriter.TYPE_UNINIT) { -++ item.intVal = getNewOffset(allIndexes, allSizes, 0, -++ item.intVal); -++ } -++ } -++ } -++ // The stack map frames are not serialized yet, so we don't need -++ // to update them. They will be serialized in visitMaxs. -++ } else if (frameCount > 0) { -++ /* -++ * Resizing an existing stack map frame table is really hard. Not -++ * only the table must be parsed to update the offets, but new -++ * frames may be needed for jump instructions that were inserted by -++ * this method. And updating the offsets or inserting frames can -++ * change the format of the following frames, in case of packed -++ * frames. In practice the whole table must be recomputed. For this -++ * the frames are marked as potentially invalid. This will cause the -++ * whole class to be reread and rewritten with the COMPUTE_FRAMES -++ * option (see the ClassWriter.toByteArray method). This is not very -++ * efficient but is much easier and requires much less code than any -++ * other method I can think of. -++ */ -++ cw.invalidFrames = true; -++ } -++ // updates the exception handler block labels -++ Handler h = firstHandler; -++ while (h != null) { -++ getNewOffset(allIndexes, allSizes, h.start); -++ getNewOffset(allIndexes, allSizes, h.end); -++ getNewOffset(allIndexes, allSizes, h.handler); -++ h = h.next; -++ } -++ // updates the instructions addresses in the -++ // local var and line number tables -++ for (i = 0; i < 2; ++i) { -++ ByteVector bv = i == 0 ? localVar : localVarType; -++ if (bv != null) { -++ b = bv.data; -++ u = 0; -++ while (u < bv.length) { -++ label = readUnsignedShort(b, u); -++ newOffset = getNewOffset(allIndexes, allSizes, 0, label); -++ writeShort(b, u, newOffset); -++ label += readUnsignedShort(b, u + 2); -++ newOffset = getNewOffset(allIndexes, allSizes, 0, label) -++ - newOffset; -++ writeShort(b, u + 2, newOffset); -++ u += 10; -++ } -++ } -++ } -++ if (lineNumber != null) { -++ b = lineNumber.data; -++ u = 0; -++ while (u < lineNumber.length) { -++ writeShort( -++ b, -++ u, -++ getNewOffset(allIndexes, allSizes, 0, -++ readUnsignedShort(b, u))); -++ u += 4; -++ } -++ } -++ // updates the labels of the other attributes -++ Attribute attr = cattrs; -++ while (attr != null) { -++ Label[] labels = attr.getLabels(); -++ if (labels != null) { -++ for (i = labels.length - 1; i >= 0; --i) { -++ getNewOffset(allIndexes, allSizes, labels[i]); -++ } -++ } -++ attr = attr.next; -++ } -++ -++ // replaces old bytecodes with new ones -++ code = newCode; -++ } -++ -++ /** -++ * Reads an unsigned short value in the given byte array. -++ * -++ * @param b -++ * a byte array. -++ * @param index -++ * the start index of the value to be read. -++ * @return the read value. -++ */ -++ static int readUnsignedShort(final byte[] b, final int index) { -++ return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF); -++ } -++ -++ /** -++ * Reads a signed short value in the given byte array. -++ * -++ * @param b -++ * a byte array. -++ * @param index -++ * the start index of the value to be read. -++ * @return the read value. -++ */ -++ static short readShort(final byte[] b, final int index) { -++ return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF)); -++ } -++ -++ /** -++ * Reads a signed int value in the given byte array. -++ * -++ * @param b -++ * a byte array. -++ * @param index -++ * the start index of the value to be read. -++ * @return the read value. -++ */ -++ static int readInt(final byte[] b, final int index) { -++ return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16) -++ | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF); -++ } -++ -++ /** -++ * Writes a short value in the given byte array. -++ * -++ * @param b -++ * a byte array. -++ * @param index -++ * where the first byte of the short value must be written. -++ * @param s -++ * the value to be written in the given byte array. -++ */ -++ static void writeShort(final byte[] b, final int index, final int s) { -++ b[index] = (byte) (s >>> 8); -++ b[index + 1] = (byte) s; -++ } -++ -++ /** -++ * Computes the future value of a bytecode offset. -++ *

-++ * Note: it is possible to have several entries for the same instruction in -++ * the indexes and sizes: two entries (index=a,size=b) and -++ * (index=a,size=b') are equivalent to a single entry (index=a,size=b+b'). -++ * -++ * @param indexes -++ * current positions of the instructions to be resized. Each -++ * instruction must be designated by the index of its last -++ * byte, plus one (or, in other words, by the index of the -++ * first byte of the next instruction). -++ * @param sizes -++ * the number of bytes to be added to the above -++ * instructions. More precisely, for each i < len, -++ * sizes[i] bytes will be added at the end of the -++ * instruction designated by indexes[i] or, if -++ * sizes[i] is negative, the last | -++ * sizes[i]| bytes of the instruction will be removed -++ * (the instruction size must not become negative or -++ * null). -++ * @param begin -++ * index of the first byte of the source instruction. -++ * @param end -++ * index of the first byte of the target instruction. -++ * @return the future value of the given bytecode offset. -++ */ -++ static int getNewOffset(final int[] indexes, final int[] sizes, -++ final int begin, final int end) { -++ int offset = end - begin; -++ for (int i = 0; i < indexes.length; ++i) { -++ if (begin < indexes[i] && indexes[i] <= end) { -++ // forward jump -++ offset += sizes[i]; -++ } else if (end < indexes[i] && indexes[i] <= begin) { -++ // backward jump -++ offset -= sizes[i]; -++ } -++ } -++ return offset; -++ } -++ -++ /** -++ * Updates the offset of the given label. -++ * -++ * @param indexes -++ * current positions of the instructions to be resized. Each -++ * instruction must be designated by the index of its last -++ * byte, plus one (or, in other words, by the index of the -++ * first byte of the next instruction). -++ * @param sizes -++ * the number of bytes to be added to the above -++ * instructions. More precisely, for each i < len, -++ * sizes[i] bytes will be added at the end of the -++ * instruction designated by indexes[i] or, if -++ * sizes[i] is negative, the last | -++ * sizes[i]| bytes of the instruction will be removed -++ * (the instruction size must not become negative or -++ * null). -++ * @param label -++ * the label whose offset must be updated. -++ */ -++ static void getNewOffset(final int[] indexes, final int[] sizes, -++ final Label label) { -++ if ((label.status & Label.RESIZED) == 0) { -++ label.position = getNewOffset(indexes, sizes, 0, label.position); -++ label.status |= Label.RESIZED; -++ } -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/Opcodes.java b/contrib/asm/src/org/objectweb/asm/Opcodes.java -+new file mode 100644 -+index 0000000..e5c2b33 -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/Opcodes.java -+@@ -0,0 +1,361 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * Defines the JVM opcodes, access flags and array type codes. This interface -++ * does not define all the JVM opcodes because some opcodes are automatically -++ * handled. For example, the xLOAD and xSTORE opcodes are automatically replaced -++ * by xLOAD_n and xSTORE_n opcodes when possible. The xLOAD_n and xSTORE_n -++ * opcodes are therefore not defined in this interface. Likewise for LDC, -++ * automatically replaced by LDC_W or LDC2_W when necessary, WIDE, GOTO_W and -++ * JSR_W. -++ * -++ * @author Eric Bruneton -++ * @author Eugene Kuleshov -++ */ -++public interface Opcodes { -++ -++ // ASM API versions -++ -++ int ASM4 = 4 << 16 | 0 << 8 | 0; -++ int ASM5 = 5 << 16 | 0 << 8 | 0; -++ -++ // versions -++ -++ int V1_1 = 3 << 16 | 45; -++ int V1_2 = 0 << 16 | 46; -++ int V1_3 = 0 << 16 | 47; -++ int V1_4 = 0 << 16 | 48; -++ int V1_5 = 0 << 16 | 49; -++ int V1_6 = 0 << 16 | 50; -++ int V1_7 = 0 << 16 | 51; -++ int V1_8 = 0 << 16 | 52; -++ -++ // access flags -++ -++ int ACC_PUBLIC = 0x0001; // class, field, method -++ int ACC_PRIVATE = 0x0002; // class, field, method -++ int ACC_PROTECTED = 0x0004; // class, field, method -++ int ACC_STATIC = 0x0008; // field, method -++ int ACC_FINAL = 0x0010; // class, field, method, parameter -++ int ACC_SUPER = 0x0020; // class -++ int ACC_SYNCHRONIZED = 0x0020; // method -++ int ACC_VOLATILE = 0x0040; // field -++ int ACC_BRIDGE = 0x0040; // method -++ int ACC_VARARGS = 0x0080; // method -++ int ACC_TRANSIENT = 0x0080; // field -++ int ACC_NATIVE = 0x0100; // method -++ int ACC_INTERFACE = 0x0200; // class -++ int ACC_ABSTRACT = 0x0400; // class, method -++ int ACC_STRICT = 0x0800; // method -++ int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter -++ int ACC_ANNOTATION = 0x2000; // class -++ int ACC_ENUM = 0x4000; // class(?) field inner -++ int ACC_MANDATED = 0x8000; // parameter -++ -++ // ASM specific pseudo access flags -++ -++ int ACC_DEPRECATED = 0x20000; // class, field, method -++ -++ // types for NEWARRAY -++ -++ int T_BOOLEAN = 4; -++ int T_CHAR = 5; -++ int T_FLOAT = 6; -++ int T_DOUBLE = 7; -++ int T_BYTE = 8; -++ int T_SHORT = 9; -++ int T_INT = 10; -++ int T_LONG = 11; -++ -++ // tags for Handle -++ -++ int H_GETFIELD = 1; -++ int H_GETSTATIC = 2; -++ int H_PUTFIELD = 3; -++ int H_PUTSTATIC = 4; -++ int H_INVOKEVIRTUAL = 5; -++ int H_INVOKESTATIC = 6; -++ int H_INVOKESPECIAL = 7; -++ int H_NEWINVOKESPECIAL = 8; -++ int H_INVOKEINTERFACE = 9; -++ -++ // stack map frame types -++ -++ /** -++ * Represents an expanded frame. See {@link ClassReader#EXPAND_FRAMES}. -++ */ -++ int F_NEW = -1; -++ -++ /** -++ * Represents a compressed frame with complete frame data. -++ */ -++ int F_FULL = 0; -++ -++ /** -++ * Represents a compressed frame where locals are the same as the locals in -++ * the previous frame, except that additional 1-3 locals are defined, and -++ * with an empty stack. -++ */ -++ int F_APPEND = 1; -++ -++ /** -++ * Represents a compressed frame where locals are the same as the locals in -++ * the previous frame, except that the last 1-3 locals are absent and with -++ * an empty stack. -++ */ -++ int F_CHOP = 2; -++ -++ /** -++ * Represents a compressed frame with exactly the same locals as the -++ * previous frame and with an empty stack. -++ */ -++ int F_SAME = 3; -++ -++ /** -++ * Represents a compressed frame with exactly the same locals as the -++ * previous frame and with a single value on the stack. -++ */ -++ int F_SAME1 = 4; -++ -++ Integer TOP = new Integer(0); -++ Integer INTEGER = new Integer(1); -++ Integer FLOAT = new Integer(2); -++ Integer DOUBLE = new Integer(3); -++ Integer LONG = new Integer(4); -++ Integer NULL = new Integer(5); -++ Integer UNINITIALIZED_THIS = new Integer(6); -++ -++ // opcodes // visit method (- = idem) -++ -++ int NOP = 0; // visitInsn -++ int ACONST_NULL = 1; // - -++ int ICONST_M1 = 2; // - -++ int ICONST_0 = 3; // - -++ int ICONST_1 = 4; // - -++ int ICONST_2 = 5; // - -++ int ICONST_3 = 6; // - -++ int ICONST_4 = 7; // - -++ int ICONST_5 = 8; // - -++ int LCONST_0 = 9; // - -++ int LCONST_1 = 10; // - -++ int FCONST_0 = 11; // - -++ int FCONST_1 = 12; // - -++ int FCONST_2 = 13; // - -++ int DCONST_0 = 14; // - -++ int DCONST_1 = 15; // - -++ int BIPUSH = 16; // visitIntInsn -++ int SIPUSH = 17; // - -++ int LDC = 18; // visitLdcInsn -++ // int LDC_W = 19; // - -++ // int LDC2_W = 20; // - -++ int ILOAD = 21; // visitVarInsn -++ int LLOAD = 22; // - -++ int FLOAD = 23; // - -++ int DLOAD = 24; // - -++ int ALOAD = 25; // - -++ // int ILOAD_0 = 26; // - -++ // int ILOAD_1 = 27; // - -++ // int ILOAD_2 = 28; // - -++ // int ILOAD_3 = 29; // - -++ // int LLOAD_0 = 30; // - -++ // int LLOAD_1 = 31; // - -++ // int LLOAD_2 = 32; // - -++ // int LLOAD_3 = 33; // - -++ // int FLOAD_0 = 34; // - -++ // int FLOAD_1 = 35; // - -++ // int FLOAD_2 = 36; // - -++ // int FLOAD_3 = 37; // - -++ // int DLOAD_0 = 38; // - -++ // int DLOAD_1 = 39; // - -++ // int DLOAD_2 = 40; // - -++ // int DLOAD_3 = 41; // - -++ // int ALOAD_0 = 42; // - -++ // int ALOAD_1 = 43; // - -++ // int ALOAD_2 = 44; // - -++ // int ALOAD_3 = 45; // - -++ int IALOAD = 46; // visitInsn -++ int LALOAD = 47; // - -++ int FALOAD = 48; // - -++ int DALOAD = 49; // - -++ int AALOAD = 50; // - -++ int BALOAD = 51; // - -++ int CALOAD = 52; // - -++ int SALOAD = 53; // - -++ int ISTORE = 54; // visitVarInsn -++ int LSTORE = 55; // - -++ int FSTORE = 56; // - -++ int DSTORE = 57; // - -++ int ASTORE = 58; // - -++ // int ISTORE_0 = 59; // - -++ // int ISTORE_1 = 60; // - -++ // int ISTORE_2 = 61; // - -++ // int ISTORE_3 = 62; // - -++ // int LSTORE_0 = 63; // - -++ // int LSTORE_1 = 64; // - -++ // int LSTORE_2 = 65; // - -++ // int LSTORE_3 = 66; // - -++ // int FSTORE_0 = 67; // - -++ // int FSTORE_1 = 68; // - -++ // int FSTORE_2 = 69; // - -++ // int FSTORE_3 = 70; // - -++ // int DSTORE_0 = 71; // - -++ // int DSTORE_1 = 72; // - -++ // int DSTORE_2 = 73; // - -++ // int DSTORE_3 = 74; // - -++ // int ASTORE_0 = 75; // - -++ // int ASTORE_1 = 76; // - -++ // int ASTORE_2 = 77; // - -++ // int ASTORE_3 = 78; // - -++ int IASTORE = 79; // visitInsn -++ int LASTORE = 80; // - -++ int FASTORE = 81; // - -++ int DASTORE = 82; // - -++ int AASTORE = 83; // - -++ int BASTORE = 84; // - -++ int CASTORE = 85; // - -++ int SASTORE = 86; // - -++ int POP = 87; // - -++ int POP2 = 88; // - -++ int DUP = 89; // - -++ int DUP_X1 = 90; // - -++ int DUP_X2 = 91; // - -++ int DUP2 = 92; // - -++ int DUP2_X1 = 93; // - -++ int DUP2_X2 = 94; // - -++ int SWAP = 95; // - -++ int IADD = 96; // - -++ int LADD = 97; // - -++ int FADD = 98; // - -++ int DADD = 99; // - -++ int ISUB = 100; // - -++ int LSUB = 101; // - -++ int FSUB = 102; // - -++ int DSUB = 103; // - -++ int IMUL = 104; // - -++ int LMUL = 105; // - -++ int FMUL = 106; // - -++ int DMUL = 107; // - -++ int IDIV = 108; // - -++ int LDIV = 109; // - -++ int FDIV = 110; // - -++ int DDIV = 111; // - -++ int IREM = 112; // - -++ int LREM = 113; // - -++ int FREM = 114; // - -++ int DREM = 115; // - -++ int INEG = 116; // - -++ int LNEG = 117; // - -++ int FNEG = 118; // - -++ int DNEG = 119; // - -++ int ISHL = 120; // - -++ int LSHL = 121; // - -++ int ISHR = 122; // - -++ int LSHR = 123; // - -++ int IUSHR = 124; // - -++ int LUSHR = 125; // - -++ int IAND = 126; // - -++ int LAND = 127; // - -++ int IOR = 128; // - -++ int LOR = 129; // - -++ int IXOR = 130; // - -++ int LXOR = 131; // - -++ int IINC = 132; // visitIincInsn -++ int I2L = 133; // visitInsn -++ int I2F = 134; // - -++ int I2D = 135; // - -++ int L2I = 136; // - -++ int L2F = 137; // - -++ int L2D = 138; // - -++ int F2I = 139; // - -++ int F2L = 140; // - -++ int F2D = 141; // - -++ int D2I = 142; // - -++ int D2L = 143; // - -++ int D2F = 144; // - -++ int I2B = 145; // - -++ int I2C = 146; // - -++ int I2S = 147; // - -++ int LCMP = 148; // - -++ int FCMPL = 149; // - -++ int FCMPG = 150; // - -++ int DCMPL = 151; // - -++ int DCMPG = 152; // - -++ int IFEQ = 153; // visitJumpInsn -++ int IFNE = 154; // - -++ int IFLT = 155; // - -++ int IFGE = 156; // - -++ int IFGT = 157; // - -++ int IFLE = 158; // - -++ int IF_ICMPEQ = 159; // - -++ int IF_ICMPNE = 160; // - -++ int IF_ICMPLT = 161; // - -++ int IF_ICMPGE = 162; // - -++ int IF_ICMPGT = 163; // - -++ int IF_ICMPLE = 164; // - -++ int IF_ACMPEQ = 165; // - -++ int IF_ACMPNE = 166; // - -++ int GOTO = 167; // - -++ int JSR = 168; // - -++ int RET = 169; // visitVarInsn -++ int TABLESWITCH = 170; // visiTableSwitchInsn -++ int LOOKUPSWITCH = 171; // visitLookupSwitch -++ int IRETURN = 172; // visitInsn -++ int LRETURN = 173; // - -++ int FRETURN = 174; // - -++ int DRETURN = 175; // - -++ int ARETURN = 176; // - -++ int RETURN = 177; // - -++ int GETSTATIC = 178; // visitFieldInsn -++ int PUTSTATIC = 179; // - -++ int GETFIELD = 180; // - -++ int PUTFIELD = 181; // - -++ int INVOKEVIRTUAL = 182; // visitMethodInsn -++ int INVOKESPECIAL = 183; // - -++ int INVOKESTATIC = 184; // - -++ int INVOKEINTERFACE = 185; // - -++ int INVOKEDYNAMIC = 186; // visitInvokeDynamicInsn -++ int NEW = 187; // visitTypeInsn -++ int NEWARRAY = 188; // visitIntInsn -++ int ANEWARRAY = 189; // visitTypeInsn -++ int ARRAYLENGTH = 190; // visitInsn -++ int ATHROW = 191; // - -++ int CHECKCAST = 192; // visitTypeInsn -++ int INSTANCEOF = 193; // - -++ int MONITORENTER = 194; // visitInsn -++ int MONITOREXIT = 195; // - -++ // int WIDE = 196; // NOT VISITED -++ int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn -++ int IFNULL = 198; // visitJumpInsn -++ int IFNONNULL = 199; // - -++ // int GOTO_W = 200; // - -++ // int JSR_W = 201; // - -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/Type.java b/contrib/asm/src/org/objectweb/asm/Type.java -+new file mode 100644 -+index 0000000..33a8bf0 -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/Type.java -+@@ -0,0 +1,896 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++import java.lang.reflect.Constructor; -++import java.lang.reflect.Method; -++ -++/** -++ * A Java field or method type. This class can be used to make it easier to -++ * manipulate type and method descriptors. -++ * -++ * @author Eric Bruneton -++ * @author Chris Nokleberg -++ */ -++public class Type { -++ -++ /** -++ * The sort of the void type. See {@link #getSort getSort}. -++ */ -++ public static final int VOID = 0; -++ -++ /** -++ * The sort of the boolean type. See {@link #getSort getSort}. -++ */ -++ public static final int BOOLEAN = 1; -++ -++ /** -++ * The sort of the char type. See {@link #getSort getSort}. -++ */ -++ public static final int CHAR = 2; -++ -++ /** -++ * The sort of the byte type. See {@link #getSort getSort}. -++ */ -++ public static final int BYTE = 3; -++ -++ /** -++ * The sort of the short type. See {@link #getSort getSort}. -++ */ -++ public static final int SHORT = 4; -++ -++ /** -++ * The sort of the int type. See {@link #getSort getSort}. -++ */ -++ public static final int INT = 5; -++ -++ /** -++ * The sort of the float type. See {@link #getSort getSort}. -++ */ -++ public static final int FLOAT = 6; -++ -++ /** -++ * The sort of the long type. See {@link #getSort getSort}. -++ */ -++ public static final int LONG = 7; -++ -++ /** -++ * The sort of the double type. See {@link #getSort getSort}. -++ */ -++ public static final int DOUBLE = 8; -++ -++ /** -++ * The sort of array reference types. See {@link #getSort getSort}. -++ */ -++ public static final int ARRAY = 9; -++ -++ /** -++ * The sort of object reference types. See {@link #getSort getSort}. -++ */ -++ public static final int OBJECT = 10; -++ -++ /** -++ * The sort of method types. See {@link #getSort getSort}. -++ */ -++ public static final int METHOD = 11; -++ -++ /** -++ * The void type. -++ */ -++ public static final Type VOID_TYPE = new Type(VOID, null, ('V' << 24) -++ | (5 << 16) | (0 << 8) | 0, 1); -++ -++ /** -++ * The boolean type. -++ */ -++ public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, null, ('Z' << 24) -++ | (0 << 16) | (5 << 8) | 1, 1); -++ -++ /** -++ * The char type. -++ */ -++ public static final Type CHAR_TYPE = new Type(CHAR, null, ('C' << 24) -++ | (0 << 16) | (6 << 8) | 1, 1); -++ -++ /** -++ * The byte type. -++ */ -++ public static final Type BYTE_TYPE = new Type(BYTE, null, ('B' << 24) -++ | (0 << 16) | (5 << 8) | 1, 1); -++ -++ /** -++ * The short type. -++ */ -++ public static final Type SHORT_TYPE = new Type(SHORT, null, ('S' << 24) -++ | (0 << 16) | (7 << 8) | 1, 1); -++ -++ /** -++ * The int type. -++ */ -++ public static final Type INT_TYPE = new Type(INT, null, ('I' << 24) -++ | (0 << 16) | (0 << 8) | 1, 1); -++ -++ /** -++ * The float type. -++ */ -++ public static final Type FLOAT_TYPE = new Type(FLOAT, null, ('F' << 24) -++ | (2 << 16) | (2 << 8) | 1, 1); -++ -++ /** -++ * The long type. -++ */ -++ public static final Type LONG_TYPE = new Type(LONG, null, ('J' << 24) -++ | (1 << 16) | (1 << 8) | 2, 1); -++ -++ /** -++ * The double type. -++ */ -++ public static final Type DOUBLE_TYPE = new Type(DOUBLE, null, ('D' << 24) -++ | (3 << 16) | (3 << 8) | 2, 1); -++ -++ // ------------------------------------------------------------------------ -++ // Fields -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * The sort of this Java type. -++ */ -++ private final int sort; -++ -++ /** -++ * A buffer containing the internal name of this Java type. This field is -++ * only used for reference types. -++ */ -++ private final char[] buf; -++ -++ /** -++ * The offset of the internal name of this Java type in {@link #buf buf} or, -++ * for primitive types, the size, descriptor and getOpcode offsets for this -++ * type (byte 0 contains the size, byte 1 the descriptor, byte 2 the offset -++ * for IALOAD or IASTORE, byte 3 the offset for all other instructions). -++ */ -++ private final int off; -++ -++ /** -++ * The length of the internal name of this Java type. -++ */ -++ private final int len; -++ -++ // ------------------------------------------------------------------------ -++ // Constructors -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Constructs a reference type. -++ * -++ * @param sort -++ * the sort of the reference type to be constructed. -++ * @param buf -++ * a buffer containing the descriptor of the previous type. -++ * @param off -++ * the offset of this descriptor in the previous buffer. -++ * @param len -++ * the length of this descriptor. -++ */ -++ private Type(final int sort, final char[] buf, final int off, final int len) { -++ this.sort = sort; -++ this.buf = buf; -++ this.off = off; -++ this.len = len; -++ } -++ -++ /** -++ * Returns the Java type corresponding to the given type descriptor. -++ * -++ * @param typeDescriptor -++ * a field or method type descriptor. -++ * @return the Java type corresponding to the given type descriptor. -++ */ -++ public static Type getType(final String typeDescriptor) { -++ return getType(typeDescriptor.toCharArray(), 0); -++ } -++ -++ /** -++ * Returns the Java type corresponding to the given internal name. -++ * -++ * @param internalName -++ * an internal name. -++ * @return the Java type corresponding to the given internal name. -++ */ -++ public static Type getObjectType(final String internalName) { -++ char[] buf = internalName.toCharArray(); -++ return new Type(buf[0] == '[' ? ARRAY : OBJECT, buf, 0, buf.length); -++ } -++ -++ /** -++ * Returns the Java type corresponding to the given method descriptor. -++ * Equivalent to Type.getType(methodDescriptor). -++ * -++ * @param methodDescriptor -++ * a method descriptor. -++ * @return the Java type corresponding to the given method descriptor. -++ */ -++ public static Type getMethodType(final String methodDescriptor) { -++ return getType(methodDescriptor.toCharArray(), 0); -++ } -++ -++ /** -++ * Returns the Java method type corresponding to the given argument and -++ * return types. -++ * -++ * @param returnType -++ * the return type of the method. -++ * @param argumentTypes -++ * the argument types of the method. -++ * @return the Java type corresponding to the given argument and return -++ * types. -++ */ -++ public static Type getMethodType(final Type returnType, -++ final Type... argumentTypes) { -++ return getType(getMethodDescriptor(returnType, argumentTypes)); -++ } -++ -++ /** -++ * Returns the Java type corresponding to the given class. -++ * -++ * @param c -++ * a class. -++ * @return the Java type corresponding to the given class. -++ */ -++ public static Type getType(final Class c) { -++ if (c.isPrimitive()) { -++ if (c == Integer.TYPE) { -++ return INT_TYPE; -++ } else if (c == Void.TYPE) { -++ return VOID_TYPE; -++ } else if (c == Boolean.TYPE) { -++ return BOOLEAN_TYPE; -++ } else if (c == Byte.TYPE) { -++ return BYTE_TYPE; -++ } else if (c == Character.TYPE) { -++ return CHAR_TYPE; -++ } else if (c == Short.TYPE) { -++ return SHORT_TYPE; -++ } else if (c == Double.TYPE) { -++ return DOUBLE_TYPE; -++ } else if (c == Float.TYPE) { -++ return FLOAT_TYPE; -++ } else /* if (c == Long.TYPE) */{ -++ return LONG_TYPE; -++ } -++ } else { -++ return getType(getDescriptor(c)); -++ } -++ } -++ -++ /** -++ * Returns the Java method type corresponding to the given constructor. -++ * -++ * @param c -++ * a {@link Constructor Constructor} object. -++ * @return the Java method type corresponding to the given constructor. -++ */ -++ public static Type getType(final Constructor c) { -++ return getType(getConstructorDescriptor(c)); -++ } -++ -++ /** -++ * Returns the Java method type corresponding to the given method. -++ * -++ * @param m -++ * a {@link Method Method} object. -++ * @return the Java method type corresponding to the given method. -++ */ -++ public static Type getType(final Method m) { -++ return getType(getMethodDescriptor(m)); -++ } -++ -++ /** -++ * Returns the Java types corresponding to the argument types of the given -++ * method descriptor. -++ * -++ * @param methodDescriptor -++ * a method descriptor. -++ * @return the Java types corresponding to the argument types of the given -++ * method descriptor. -++ */ -++ public static Type[] getArgumentTypes(final String methodDescriptor) { -++ char[] buf = methodDescriptor.toCharArray(); -++ int off = 1; -++ int size = 0; -++ while (true) { -++ char car = buf[off++]; -++ if (car == ')') { -++ break; -++ } else if (car == 'L') { -++ while (buf[off++] != ';') { -++ } -++ ++size; -++ } else if (car != '[') { -++ ++size; -++ } -++ } -++ Type[] args = new Type[size]; -++ off = 1; -++ size = 0; -++ while (buf[off] != ')') { -++ args[size] = getType(buf, off); -++ off += args[size].len + (args[size].sort == OBJECT ? 2 : 0); -++ size += 1; -++ } -++ return args; -++ } -++ -++ /** -++ * Returns the Java types corresponding to the argument types of the given -++ * method. -++ * -++ * @param method -++ * a method. -++ * @return the Java types corresponding to the argument types of the given -++ * method. -++ */ -++ public static Type[] getArgumentTypes(final Method method) { -++ Class[] classes = method.getParameterTypes(); -++ Type[] types = new Type[classes.length]; -++ for (int i = classes.length - 1; i >= 0; --i) { -++ types[i] = getType(classes[i]); -++ } -++ return types; -++ } -++ -++ /** -++ * Returns the Java type corresponding to the return type of the given -++ * method descriptor. -++ * -++ * @param methodDescriptor -++ * a method descriptor. -++ * @return the Java type corresponding to the return type of the given -++ * method descriptor. -++ */ -++ public static Type getReturnType(final String methodDescriptor) { -++ char[] buf = methodDescriptor.toCharArray(); -++ return getType(buf, methodDescriptor.indexOf(')') + 1); -++ } -++ -++ /** -++ * Returns the Java type corresponding to the return type of the given -++ * method. -++ * -++ * @param method -++ * a method. -++ * @return the Java type corresponding to the return type of the given -++ * method. -++ */ -++ public static Type getReturnType(final Method method) { -++ return getType(method.getReturnType()); -++ } -++ -++ /** -++ * Computes the size of the arguments and of the return value of a method. -++ * -++ * @param desc -++ * the descriptor of a method. -++ * @return the size of the arguments of the method (plus one for the -++ * implicit this argument), argSize, and the size of its return -++ * value, retSize, packed into a single int i = -++ * (argSize << 2) | retSize (argSize is therefore equal to -++ * i >> 2, and retSize to i & 0x03). -++ */ -++ public static int getArgumentsAndReturnSizes(final String desc) { -++ int n = 1; -++ int c = 1; -++ while (true) { -++ char car = desc.charAt(c++); -++ if (car == ')') { -++ car = desc.charAt(c); -++ return n << 2 -++ | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1)); -++ } else if (car == 'L') { -++ while (desc.charAt(c++) != ';') { -++ } -++ n += 1; -++ } else if (car == '[') { -++ while ((car = desc.charAt(c)) == '[') { -++ ++c; -++ } -++ if (car == 'D' || car == 'J') { -++ n -= 1; -++ } -++ } else if (car == 'D' || car == 'J') { -++ n += 2; -++ } else { -++ n += 1; -++ } -++ } -++ } -++ -++ /** -++ * Returns the Java type corresponding to the given type descriptor. For -++ * method descriptors, buf is supposed to contain nothing more than the -++ * descriptor itself. -++ * -++ * @param buf -++ * a buffer containing a type descriptor. -++ * @param off -++ * the offset of this descriptor in the previous buffer. -++ * @return the Java type corresponding to the given type descriptor. -++ */ -++ private static Type getType(final char[] buf, final int off) { -++ int len; -++ switch (buf[off]) { -++ case 'V': -++ return VOID_TYPE; -++ case 'Z': -++ return BOOLEAN_TYPE; -++ case 'C': -++ return CHAR_TYPE; -++ case 'B': -++ return BYTE_TYPE; -++ case 'S': -++ return SHORT_TYPE; -++ case 'I': -++ return INT_TYPE; -++ case 'F': -++ return FLOAT_TYPE; -++ case 'J': -++ return LONG_TYPE; -++ case 'D': -++ return DOUBLE_TYPE; -++ case '[': -++ len = 1; -++ while (buf[off + len] == '[') { -++ ++len; -++ } -++ if (buf[off + len] == 'L') { -++ ++len; -++ while (buf[off + len] != ';') { -++ ++len; -++ } -++ } -++ return new Type(ARRAY, buf, off, len + 1); -++ case 'L': -++ len = 1; -++ while (buf[off + len] != ';') { -++ ++len; -++ } -++ return new Type(OBJECT, buf, off + 1, len - 1); -++ // case '(': -++ default: -++ return new Type(METHOD, buf, off, buf.length - off); -++ } -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Accessors -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Returns the sort of this Java type. -++ * -++ * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN}, {@link #CHAR CHAR}, -++ * {@link #BYTE BYTE}, {@link #SHORT SHORT}, {@link #INT INT}, -++ * {@link #FLOAT FLOAT}, {@link #LONG LONG}, {@link #DOUBLE DOUBLE}, -++ * {@link #ARRAY ARRAY}, {@link #OBJECT OBJECT} or {@link #METHOD -++ * METHOD}. -++ */ -++ public int getSort() { -++ return sort; -++ } -++ -++ /** -++ * Returns the number of dimensions of this array type. This method should -++ * only be used for an array type. -++ * -++ * @return the number of dimensions of this array type. -++ */ -++ public int getDimensions() { -++ int i = 1; -++ while (buf[off + i] == '[') { -++ ++i; -++ } -++ return i; -++ } -++ -++ /** -++ * Returns the type of the elements of this array type. This method should -++ * only be used for an array type. -++ * -++ * @return Returns the type of the elements of this array type. -++ */ -++ public Type getElementType() { -++ return getType(buf, off + getDimensions()); -++ } -++ -++ /** -++ * Returns the binary name of the class corresponding to this type. This -++ * method must not be used on method types. -++ * -++ * @return the binary name of the class corresponding to this type. -++ */ -++ public String getClassName() { -++ switch (sort) { -++ case VOID: -++ return "void"; -++ case BOOLEAN: -++ return "boolean"; -++ case CHAR: -++ return "char"; -++ case BYTE: -++ return "byte"; -++ case SHORT: -++ return "short"; -++ case INT: -++ return "int"; -++ case FLOAT: -++ return "float"; -++ case LONG: -++ return "long"; -++ case DOUBLE: -++ return "double"; -++ case ARRAY: -++ StringBuilder sb = new StringBuilder(getElementType().getClassName()); -++ for (int i = getDimensions(); i > 0; --i) { -++ sb.append("[]"); -++ } -++ return sb.toString(); -++ case OBJECT: -++ return new String(buf, off, len).replace('/', '.'); -++ default: -++ return null; -++ } -++ } -++ -++ /** -++ * Returns the internal name of the class corresponding to this object or -++ * array type. The internal name of a class is its fully qualified name (as -++ * returned by Class.getName(), where '.' are replaced by '/'. This method -++ * should only be used for an object or array type. -++ * -++ * @return the internal name of the class corresponding to this object type. -++ */ -++ public String getInternalName() { -++ return new String(buf, off, len); -++ } -++ -++ /** -++ * Returns the argument types of methods of this type. This method should -++ * only be used for method types. -++ * -++ * @return the argument types of methods of this type. -++ */ -++ public Type[] getArgumentTypes() { -++ return getArgumentTypes(getDescriptor()); -++ } -++ -++ /** -++ * Returns the return type of methods of this type. This method should only -++ * be used for method types. -++ * -++ * @return the return type of methods of this type. -++ */ -++ public Type getReturnType() { -++ return getReturnType(getDescriptor()); -++ } -++ -++ /** -++ * Returns the size of the arguments and of the return value of methods of -++ * this type. This method should only be used for method types. -++ * -++ * @return the size of the arguments (plus one for the implicit this -++ * argument), argSize, and the size of the return value, retSize, -++ * packed into a single -++ * int i = (argSize << 2) | retSize -++ * (argSize is therefore equal to i >> 2, -++ * and retSize to i & 0x03). -++ */ -++ public int getArgumentsAndReturnSizes() { -++ return getArgumentsAndReturnSizes(getDescriptor()); -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Conversion to type descriptors -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Returns the descriptor corresponding to this Java type. -++ * -++ * @return the descriptor corresponding to this Java type. -++ */ -++ public String getDescriptor() { -++ StringBuffer buf = new StringBuffer(); -++ getDescriptor(buf); -++ return buf.toString(); -++ } -++ -++ /** -++ * Returns the descriptor corresponding to the given argument and return -++ * types. -++ * -++ * @param returnType -++ * the return type of the method. -++ * @param argumentTypes -++ * the argument types of the method. -++ * @return the descriptor corresponding to the given argument and return -++ * types. -++ */ -++ public static String getMethodDescriptor(final Type returnType, -++ final Type... argumentTypes) { -++ StringBuffer buf = new StringBuffer(); -++ buf.append('('); -++ for (int i = 0; i < argumentTypes.length; ++i) { -++ argumentTypes[i].getDescriptor(buf); -++ } -++ buf.append(')'); -++ returnType.getDescriptor(buf); -++ return buf.toString(); -++ } -++ -++ /** -++ * Appends the descriptor corresponding to this Java type to the given -++ * string buffer. -++ * -++ * @param buf -++ * the string buffer to which the descriptor must be appended. -++ */ -++ private void getDescriptor(final StringBuffer buf) { -++ if (this.buf == null) { -++ // descriptor is in byte 3 of 'off' for primitive types (buf == -++ // null) -++ buf.append((char) ((off & 0xFF000000) >>> 24)); -++ } else if (sort == OBJECT) { -++ buf.append('L'); -++ buf.append(this.buf, off, len); -++ buf.append(';'); -++ } else { // sort == ARRAY || sort == METHOD -++ buf.append(this.buf, off, len); -++ } -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Direct conversion from classes to type descriptors, -++ // without intermediate Type objects -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Returns the internal name of the given class. The internal name of a -++ * class is its fully qualified name, as returned by Class.getName(), where -++ * '.' are replaced by '/'. -++ * -++ * @param c -++ * an object or array class. -++ * @return the internal name of the given class. -++ */ -++ public static String getInternalName(final Class c) { -++ return c.getName().replace('.', '/'); -++ } -++ -++ /** -++ * Returns the descriptor corresponding to the given Java type. -++ * -++ * @param c -++ * an object class, a primitive class or an array class. -++ * @return the descriptor corresponding to the given class. -++ */ -++ public static String getDescriptor(final Class c) { -++ StringBuffer buf = new StringBuffer(); -++ getDescriptor(buf, c); -++ return buf.toString(); -++ } -++ -++ /** -++ * Returns the descriptor corresponding to the given constructor. -++ * -++ * @param c -++ * a {@link Constructor Constructor} object. -++ * @return the descriptor of the given constructor. -++ */ -++ public static String getConstructorDescriptor(final Constructor c) { -++ Class[] parameters = c.getParameterTypes(); -++ StringBuffer buf = new StringBuffer(); -++ buf.append('('); -++ for (int i = 0; i < parameters.length; ++i) { -++ getDescriptor(buf, parameters[i]); -++ } -++ return buf.append(")V").toString(); -++ } -++ -++ /** -++ * Returns the descriptor corresponding to the given method. -++ * -++ * @param m -++ * a {@link Method Method} object. -++ * @return the descriptor of the given method. -++ */ -++ public static String getMethodDescriptor(final Method m) { -++ Class[] parameters = m.getParameterTypes(); -++ StringBuffer buf = new StringBuffer(); -++ buf.append('('); -++ for (int i = 0; i < parameters.length; ++i) { -++ getDescriptor(buf, parameters[i]); -++ } -++ buf.append(')'); -++ getDescriptor(buf, m.getReturnType()); -++ return buf.toString(); -++ } -++ -++ /** -++ * Appends the descriptor of the given class to the given string buffer. -++ * -++ * @param buf -++ * the string buffer to which the descriptor must be appended. -++ * @param c -++ * the class whose descriptor must be computed. -++ */ -++ private static void getDescriptor(final StringBuffer buf, final Class c) { -++ Class d = c; -++ while (true) { -++ if (d.isPrimitive()) { -++ char car; -++ if (d == Integer.TYPE) { -++ car = 'I'; -++ } else if (d == Void.TYPE) { -++ car = 'V'; -++ } else if (d == Boolean.TYPE) { -++ car = 'Z'; -++ } else if (d == Byte.TYPE) { -++ car = 'B'; -++ } else if (d == Character.TYPE) { -++ car = 'C'; -++ } else if (d == Short.TYPE) { -++ car = 'S'; -++ } else if (d == Double.TYPE) { -++ car = 'D'; -++ } else if (d == Float.TYPE) { -++ car = 'F'; -++ } else /* if (d == Long.TYPE) */{ -++ car = 'J'; -++ } -++ buf.append(car); -++ return; -++ } else if (d.isArray()) { -++ buf.append('['); -++ d = d.getComponentType(); -++ } else { -++ buf.append('L'); -++ String name = d.getName(); -++ int len = name.length(); -++ for (int i = 0; i < len; ++i) { -++ char car = name.charAt(i); -++ buf.append(car == '.' ? '/' : car); -++ } -++ buf.append(';'); -++ return; -++ } -++ } -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Corresponding size and opcodes -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Returns the size of values of this type. This method must not be used for -++ * method types. -++ * -++ * @return the size of values of this type, i.e., 2 for long and -++ * double, 0 for void and 1 otherwise. -++ */ -++ public int getSize() { -++ // the size is in byte 0 of 'off' for primitive types (buf == null) -++ return buf == null ? (off & 0xFF) : 1; -++ } -++ -++ /** -++ * Returns a JVM instruction opcode adapted to this Java type. This method -++ * must not be used for method types. -++ * -++ * @param opcode -++ * a JVM instruction opcode. This opcode must be one of ILOAD, -++ * ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, -++ * ISHL, ISHR, IUSHR, IAND, IOR, IXOR and IRETURN. -++ * @return an opcode that is similar to the given opcode, but adapted to -++ * this Java type. For example, if this type is float and -++ * opcode is IRETURN, this method returns FRETURN. -++ */ -++ public int getOpcode(final int opcode) { -++ if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) { -++ // the offset for IALOAD or IASTORE is in byte 1 of 'off' for -++ // primitive types (buf == null) -++ return opcode + (buf == null ? (off & 0xFF00) >> 8 : 4); -++ } else { -++ // the offset for other instructions is in byte 2 of 'off' for -++ // primitive types (buf == null) -++ return opcode + (buf == null ? (off & 0xFF0000) >> 16 : 4); -++ } -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Equals, hashCode and toString -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Tests if the given object is equal to this type. -++ * -++ * @param o -++ * the object to be compared to this type. -++ * @return true if the given object is equal to this type. -++ */ -++ @Override -++ public boolean equals(final Object o) { -++ if (this == o) { -++ return true; -++ } -++ if (!(o instanceof Type)) { -++ return false; -++ } -++ Type t = (Type) o; -++ if (sort != t.sort) { -++ return false; -++ } -++ if (sort >= ARRAY) { -++ if (len != t.len) { -++ return false; -++ } -++ for (int i = off, j = t.off, end = i + len; i < end; i++, j++) { -++ if (buf[i] != t.buf[j]) { -++ return false; -++ } -++ } -++ } -++ return true; -++ } -++ -++ /** -++ * Returns a hash code value for this type. -++ * -++ * @return a hash code value for this type. -++ */ -++ @Override -++ public int hashCode() { -++ int hc = 13 * sort; -++ if (sort >= ARRAY) { -++ for (int i = off, end = i + len; i < end; i++) { -++ hc = 17 * (hc + buf[i]); -++ } -++ } -++ return hc; -++ } -++ -++ /** -++ * Returns a string representation of this type. -++ * -++ * @return the descriptor of this type. -++ */ -++ @Override -++ public String toString() { -++ return getDescriptor(); -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/TypePath.java b/contrib/asm/src/org/objectweb/asm/TypePath.java -+new file mode 100644 -+index 0000000..d9c99b1 -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/TypePath.java -+@@ -0,0 +1,196 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2013 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++ -++package org.objectweb.asm; -++ -++/** -++ * The path to a type argument, wildcard bound, array element type, or static -++ * inner type within an enclosing type. -++ * -++ * @author Eric Bruneton -++ */ -++public class TypePath { -++ -++ /** -++ * A type path step that steps into the element type of an array type. See -++ * {@link #getStep getStep}. -++ */ -++ public final static int ARRAY_ELEMENT = 0; -++ -++ /** -++ * A type path step that steps into the nested type of a class type. See -++ * {@link #getStep getStep}. -++ */ -++ public final static int INNER_TYPE = 1; -++ -++ /** -++ * A type path step that steps into the bound of a wildcard type. See -++ * {@link #getStep getStep}. -++ */ -++ public final static int WILDCARD_BOUND = 2; -++ -++ /** -++ * A type path step that steps into a type argument of a generic type. See -++ * {@link #getStep getStep}. -++ */ -++ public final static int TYPE_ARGUMENT = 3; -++ -++ /** -++ * The byte array where the path is stored, in Java class file format. -++ */ -++ byte[] b; -++ -++ /** -++ * The offset of the first byte of the type path in 'b'. -++ */ -++ int offset; -++ -++ /** -++ * Creates a new type path. -++ * -++ * @param b -++ * the byte array containing the type path in Java class file -++ * format. -++ * @param offset -++ * the offset of the first byte of the type path in 'b'. -++ */ -++ TypePath(byte[] b, int offset) { -++ this.b = b; -++ this.offset = offset; -++ } -++ -++ /** -++ * Returns the length of this path. -++ * -++ * @return the length of this path. -++ */ -++ public int getLength() { -++ return b[offset]; -++ } -++ -++ /** -++ * Returns the value of the given step of this path. -++ * -++ * @param index -++ * an index between 0 and {@link #getLength()}, exclusive. -++ * @return {@link #ARRAY_ELEMENT ARRAY_ELEMENT}, {@link #INNER_TYPE -++ * INNER_TYPE}, {@link #WILDCARD_BOUND WILDCARD_BOUND}, or -++ * {@link #TYPE_ARGUMENT TYPE_ARGUMENT}. -++ */ -++ public int getStep(int index) { -++ return b[offset + 2 * index + 1]; -++ } -++ -++ /** -++ * Returns the index of the type argument that the given step is stepping -++ * into. This method should only be used for steps whose value is -++ * {@link #TYPE_ARGUMENT TYPE_ARGUMENT}. -++ * -++ * @param index -++ * an index between 0 and {@link #getLength()}, exclusive. -++ * @return the index of the type argument that the given step is stepping -++ * into. -++ */ -++ public int getStepArgument(int index) { -++ return b[offset + 2 * index + 2]; -++ } -++ -++ /** -++ * Converts a type path in string form, in the format used by -++ * {@link #toString()}, into a TypePath object. -++ * -++ * @param typePath -++ * a type path in string form, in the format used by -++ * {@link #toString()}. May be null or empty. -++ * @return the corresponding TypePath object, or null if the path is empty. -++ */ -++ public static TypePath fromString(final String typePath) { -++ if (typePath == null || typePath.length() == 0) { -++ return null; -++ } -++ int n = typePath.length(); -++ ByteVector out = new ByteVector(n); -++ out.putByte(0); -++ for (int i = 0; i < n;) { -++ char c = typePath.charAt(i++); -++ if (c == '[') { -++ out.put11(ARRAY_ELEMENT, 0); -++ } else if (c == '.') { -++ out.put11(INNER_TYPE, 0); -++ } else if (c == '*') { -++ out.put11(WILDCARD_BOUND, 0); -++ } else if (c >= '0' && c <= '9') { -++ int typeArg = c - '0'; -++ while (i < n && (c = typePath.charAt(i)) >= '0' && c <= '9') { -++ typeArg = typeArg * 10 + c - '0'; -++ i += 1; -++ } -++ if (i < n && typePath.charAt(i) == ';') { -++ i += 1; -++ } -++ out.put11(TYPE_ARGUMENT, typeArg); -++ } -++ } -++ out.data[0] = (byte) (out.length / 2); -++ return new TypePath(out.data, 0); -++ } -++ -++ /** -++ * Returns a string representation of this type path. {@link #ARRAY_ELEMENT -++ * ARRAY_ELEMENT} steps are represented with '[', {@link #INNER_TYPE -++ * INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND WILDCARD_BOUND} steps -++ * with '*' and {@link #TYPE_ARGUMENT TYPE_ARGUMENT} steps with their type -++ * argument index in decimal form followed by ';'. -++ */ -++ @Override -++ public String toString() { -++ int length = getLength(); -++ StringBuilder result = new StringBuilder(length * 2); -++ for (int i = 0; i < length; ++i) { -++ switch (getStep(i)) { -++ case ARRAY_ELEMENT: -++ result.append('['); -++ break; -++ case INNER_TYPE: -++ result.append('.'); -++ break; -++ case WILDCARD_BOUND: -++ result.append('*'); -++ break; -++ case TYPE_ARGUMENT: -++ result.append(getStepArgument(i)).append(';'); -++ break; -++ default: -++ result.append('_'); -++ } -++ } -++ return result.toString(); -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/TypeReference.java b/contrib/asm/src/org/objectweb/asm/TypeReference.java -+new file mode 100644 -+index 0000000..dff76c0 -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/TypeReference.java -+@@ -0,0 +1,452 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2013 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++ -++package org.objectweb.asm; -++ -++/** -++ * A reference to a type appearing in a class, field or method declaration, or -++ * on an instruction. Such a reference designates the part of the class where -++ * the referenced type is appearing (e.g. an 'extends', 'implements' or 'throws' -++ * clause, a 'new' instruction, a 'catch' clause, a type cast, a local variable -++ * declaration, etc). -++ * -++ * @author Eric Bruneton -++ */ -++public class TypeReference { -++ -++ /** -++ * The sort of type references that target a type parameter of a generic -++ * class. See {@link #getSort getSort}. -++ */ -++ public final static int CLASS_TYPE_PARAMETER = 0x00; -++ -++ /** -++ * The sort of type references that target a type parameter of a generic -++ * method. See {@link #getSort getSort}. -++ */ -++ public final static int METHOD_TYPE_PARAMETER = 0x01; -++ -++ /** -++ * The sort of type references that target the super class of a class or one -++ * of the interfaces it implements. See {@link #getSort getSort}. -++ */ -++ public final static int CLASS_EXTENDS = 0x10; -++ -++ /** -++ * The sort of type references that target a bound of a type parameter of a -++ * generic class. See {@link #getSort getSort}. -++ */ -++ public final static int CLASS_TYPE_PARAMETER_BOUND = 0x11; -++ -++ /** -++ * The sort of type references that target a bound of a type parameter of a -++ * generic method. See {@link #getSort getSort}. -++ */ -++ public final static int METHOD_TYPE_PARAMETER_BOUND = 0x12; -++ -++ /** -++ * The sort of type references that target the type of a field. See -++ * {@link #getSort getSort}. -++ */ -++ public final static int FIELD = 0x13; -++ -++ /** -++ * The sort of type references that target the return type of a method. See -++ * {@link #getSort getSort}. -++ */ -++ public final static int METHOD_RETURN = 0x14; -++ -++ /** -++ * The sort of type references that target the receiver type of a method. -++ * See {@link #getSort getSort}. -++ */ -++ public final static int METHOD_RECEIVER = 0x15; -++ -++ /** -++ * The sort of type references that target the type of a formal parameter of -++ * a method. See {@link #getSort getSort}. -++ */ -++ public final static int METHOD_FORMAL_PARAMETER = 0x16; -++ -++ /** -++ * The sort of type references that target the type of an exception declared -++ * in the throws clause of a method. See {@link #getSort getSort}. -++ */ -++ public final static int THROWS = 0x17; -++ -++ /** -++ * The sort of type references that target the type of a local variable in a -++ * method. See {@link #getSort getSort}. -++ */ -++ public final static int LOCAL_VARIABLE = 0x40; -++ -++ /** -++ * The sort of type references that target the type of a resource variable -++ * in a method. See {@link #getSort getSort}. -++ */ -++ public final static int RESOURCE_VARIABLE = 0x41; -++ -++ /** -++ * The sort of type references that target the type of the exception of a -++ * 'catch' clause in a method. See {@link #getSort getSort}. -++ */ -++ public final static int EXCEPTION_PARAMETER = 0x42; -++ -++ /** -++ * The sort of type references that target the type declared in an -++ * 'instanceof' instruction. See {@link #getSort getSort}. -++ */ -++ public final static int INSTANCEOF = 0x43; -++ -++ /** -++ * The sort of type references that target the type of the object created by -++ * a 'new' instruction. See {@link #getSort getSort}. -++ */ -++ public final static int NEW = 0x44; -++ -++ /** -++ * The sort of type references that target the receiver type of a -++ * constructor reference. See {@link #getSort getSort}. -++ */ -++ public final static int CONSTRUCTOR_REFERENCE = 0x45; -++ -++ /** -++ * The sort of type references that target the receiver type of a method -++ * reference. See {@link #getSort getSort}. -++ */ -++ public final static int METHOD_REFERENCE = 0x46; -++ -++ /** -++ * The sort of type references that target the type declared in an explicit -++ * or implicit cast instruction. See {@link #getSort getSort}. -++ */ -++ public final static int CAST = 0x47; -++ -++ /** -++ * The sort of type references that target a type parameter of a generic -++ * constructor in a constructor call. See {@link #getSort getSort}. -++ */ -++ public final static int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48; -++ -++ /** -++ * The sort of type references that target a type parameter of a generic -++ * method in a method call. See {@link #getSort getSort}. -++ */ -++ public final static int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49; -++ -++ /** -++ * The sort of type references that target a type parameter of a generic -++ * constructor in a constructor reference. See {@link #getSort getSort}. -++ */ -++ public final static int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A; -++ -++ /** -++ * The sort of type references that target a type parameter of a generic -++ * method in a method reference. See {@link #getSort getSort}. -++ */ -++ public final static int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B; -++ -++ /** -++ * The type reference value in Java class file format. -++ */ -++ private int value; -++ -++ /** -++ * Creates a new TypeReference. -++ * -++ * @param typeRef -++ * the int encoded value of the type reference, as received in a -++ * visit method related to type annotations, like -++ * visitTypeAnnotation. -++ */ -++ public TypeReference(int typeRef) { -++ this.value = typeRef; -++ } -++ -++ /** -++ * Returns a type reference of the given sort. -++ * -++ * @param sort -++ * {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN}, -++ * {@link #METHOD_RECEIVER METHOD_RECEIVER}, -++ * {@link #LOCAL_VARIABLE LOCAL_VARIABLE}, -++ * {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE}, -++ * {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW}, -++ * {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, or -++ * {@link #METHOD_REFERENCE METHOD_REFERENCE}. -++ * @return a type reference of the given sort. -++ */ -++ public static TypeReference newTypeReference(int sort) { -++ return new TypeReference(sort << 24); -++ } -++ -++ /** -++ * Returns a reference to a type parameter of a generic class or method. -++ * -++ * @param sort -++ * {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or -++ * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}. -++ * @param paramIndex -++ * the type parameter index. -++ * @return a reference to the given generic class or method type parameter. -++ */ -++ public static TypeReference newTypeParameterReference(int sort, -++ int paramIndex) { -++ return new TypeReference((sort << 24) | (paramIndex << 16)); -++ } -++ -++ /** -++ * Returns a reference to a type parameter bound of a generic class or -++ * method. -++ * -++ * @param sort -++ * {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or -++ * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}. -++ * @param paramIndex -++ * the type parameter index. -++ * @param boundIndex -++ * the type bound index within the above type parameters. -++ * @return a reference to the given generic class or method type parameter -++ * bound. -++ */ -++ public static TypeReference newTypeParameterBoundReference(int sort, -++ int paramIndex, int boundIndex) { -++ return new TypeReference((sort << 24) | (paramIndex << 16) -++ | (boundIndex << 8)); -++ } -++ -++ /** -++ * Returns a reference to the super class or to an interface of the -++ * 'implements' clause of a class. -++ * -++ * @param itfIndex -++ * the index of an interface in the 'implements' clause of a -++ * class, or -1 to reference the super class of the class. -++ * @return a reference to the given super type of a class. -++ */ -++ public static TypeReference newSuperTypeReference(int itfIndex) { -++ itfIndex &= 0xFFFF; -++ return new TypeReference((CLASS_EXTENDS << 24) | (itfIndex << 8)); -++ } -++ -++ /** -++ * Returns a reference to the type of a formal parameter of a method. -++ * -++ * @param paramIndex -++ * the formal parameter index. -++ * -++ * @return a reference to the type of the given method formal parameter. -++ */ -++ public static TypeReference newFormalParameterReference(int paramIndex) { -++ return new TypeReference((METHOD_FORMAL_PARAMETER << 24) -++ | (paramIndex << 16)); -++ } -++ -++ /** -++ * Returns a reference to the type of an exception, in a 'throws' clause of -++ * a method. -++ * -++ * @param exceptionIndex -++ * the index of an exception in a 'throws' clause of a method. -++ * -++ * @return a reference to the type of the given exception. -++ */ -++ public static TypeReference newExceptionReference(int exceptionIndex) { -++ return new TypeReference((THROWS << 24) | (exceptionIndex << 8)); -++ } -++ -++ /** -++ * Returns a reference to the type of the exception declared in a 'catch' -++ * clause of a method. -++ * -++ * @param tryCatchBlockIndex -++ * the index of a try catch block (using the order in which they -++ * are visited with visitTryCatchBlock). -++ * -++ * @return a reference to the type of the given exception. -++ */ -++ public static TypeReference newTryCatchReference(int tryCatchBlockIndex) { -++ return new TypeReference((EXCEPTION_PARAMETER << 24) -++ | (tryCatchBlockIndex << 8)); -++ } -++ -++ /** -++ * Returns a reference to the type of a type argument in a constructor or -++ * method call or reference. -++ * -++ * @param sort -++ * {@link #CAST CAST}, -++ * {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT -++ * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, -++ * {@link #METHOD_INVOCATION_TYPE_ARGUMENT -++ * METHOD_INVOCATION_TYPE_ARGUMENT}, -++ * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT -++ * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or -++ * {@link #METHOD_REFERENCE_TYPE_ARGUMENT -++ * METHOD_REFERENCE_TYPE_ARGUMENT}. -++ * @param argIndex -++ * the type argument index. -++ * -++ * @return a reference to the type of the given type argument. -++ */ -++ public static TypeReference newTypeArgumentReference(int sort, int argIndex) { -++ return new TypeReference((sort << 24) | argIndex); -++ } -++ -++ /** -++ * Returns the sort of this type reference. -++ * -++ * @return {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, -++ * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}, -++ * {@link #CLASS_EXTENDS CLASS_EXTENDS}, -++ * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND}, -++ * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}, -++ * {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN}, -++ * {@link #METHOD_RECEIVER METHOD_RECEIVER}, -++ * {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}, -++ * {@link #THROWS THROWS}, {@link #LOCAL_VARIABLE LOCAL_VARIABLE}, -++ * {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE}, -++ * {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER}, -++ * {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW}, -++ * {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, -++ * {@link #METHOD_REFERENCE METHOD_REFERENCE}, {@link #CAST CAST}, -++ * {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT -++ * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, -++ * {@link #METHOD_INVOCATION_TYPE_ARGUMENT -++ * METHOD_INVOCATION_TYPE_ARGUMENT}, -++ * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT -++ * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or -++ * {@link #METHOD_REFERENCE_TYPE_ARGUMENT -++ * METHOD_REFERENCE_TYPE_ARGUMENT}. -++ */ -++ public int getSort() { -++ return value >>> 24; -++ } -++ -++ /** -++ * Returns the index of the type parameter referenced by this type -++ * reference. This method must only be used for type references whose sort -++ * is {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, -++ * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}, -++ * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or -++ * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}. -++ * -++ * @return a type parameter index. -++ */ -++ public int getTypeParameterIndex() { -++ return (value & 0x00FF0000) >> 16; -++ } -++ -++ /** -++ * Returns the index of the type parameter bound, within the type parameter -++ * {@link #getTypeParameterIndex}, referenced by this type reference. This -++ * method must only be used for type references whose sort is -++ * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or -++ * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}. -++ * -++ * @return a type parameter bound index. -++ */ -++ public int getTypeParameterBoundIndex() { -++ return (value & 0x0000FF00) >> 8; -++ } -++ -++ /** -++ * Returns the index of the "super type" of a class that is referenced by -++ * this type reference. This method must only be used for type references -++ * whose sort is {@link #CLASS_EXTENDS CLASS_EXTENDS}. -++ * -++ * @return the index of an interface in the 'implements' clause of a class, -++ * or -1 if this type reference references the type of the super -++ * class. -++ */ -++ public int getSuperTypeIndex() { -++ return (short) ((value & 0x00FFFF00) >> 8); -++ } -++ -++ /** -++ * Returns the index of the formal parameter whose type is referenced by -++ * this type reference. This method must only be used for type references -++ * whose sort is {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}. -++ * -++ * @return a formal parameter index. -++ */ -++ public int getFormalParameterIndex() { -++ return (value & 0x00FF0000) >> 16; -++ } -++ -++ /** -++ * Returns the index of the exception, in a 'throws' clause of a method, -++ * whose type is referenced by this type reference. This method must only be -++ * used for type references whose sort is {@link #THROWS THROWS}. -++ * -++ * @return the index of an exception in the 'throws' clause of a method. -++ */ -++ public int getExceptionIndex() { -++ return (value & 0x00FFFF00) >> 8; -++ } -++ -++ /** -++ * Returns the index of the try catch block (using the order in which they -++ * are visited with visitTryCatchBlock), whose 'catch' type is referenced by -++ * this type reference. This method must only be used for type references -++ * whose sort is {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER} . -++ * -++ * @return the index of an exception in the 'throws' clause of a method. -++ */ -++ public int getTryCatchBlockIndex() { -++ return (value & 0x00FFFF00) >> 8; -++ } -++ -++ /** -++ * Returns the index of the type argument referenced by this type reference. -++ * This method must only be used for type references whose sort is -++ * {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT -++ * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, -++ * {@link #METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT}, -++ * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT -++ * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or -++ * {@link #METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}. -++ * -++ * @return a type parameter index. -++ */ -++ public int getTypeArgumentIndex() { -++ return value & 0xFF; -++ } -++ -++ /** -++ * Returns the int encoded value of this type reference, suitable for use in -++ * visit methods related to type annotations, like visitTypeAnnotation. -++ * -++ * @return the int encoded value of this type reference. -++ */ -++ public int getValue() { -++ return value; -++ } -++} +diff --git a/includes/inttypes.h b/includes/inttypes.h +new file mode 100644 +index 0000000..ead903f @@ -70463,4081 +50816,6 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 ++ ++ +\ No newline at end of file -+diff --git a/src/devtools/bdj_test.c b/src/devtools/bdj_test.c -+new file mode 100644 -+index 0000000..d9ebd16 -+--- /dev/null -++++ b/src/devtools/bdj_test.c -+@@ -0,0 +1,67 @@ -++/* -++ * This file is part of libbluray -++ * Copyright (C) 2010 William Hahne -++ * -++ * This program is free software; you can redistribute it and/or -++ * modify it under the terms of the GNU General Public License -++ * as published by the Free Software Foundation; either version 2 -++ * of the License, or (at your option) any later version. -++ * -++ * This program is distributed in the hope that it will be useful, -++ * but WITHOUT ANY WARRANTY; without even the implied warranty of -++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -++ * GNU General Public License for more details. -++ * -++ * You should have received a copy of the GNU General Public License -++ * along with this program. If not, see . -++ * -++ * In addition, as a special exception, the copyright holders of libbluray -++ * gives permission to link the code of its release of libbluray with the -++ * OpenSSL project's "OpenSSL" library (or with modified versions of it -++ * that use the same license as the "OpenSSL" library), and distribute -++ * the linked executables. You must obey the GNU General Public License -++ * in all respects for all of the code used other than "OpenSSL". If you -++ * modify this file, you may extend this exception to your version of the -++ * file, but you are not obligated to do so. If you do not wish to do -++ * so, delete this exception statement from your version. -++ */ -++ -++#include -++#include -++#include -++ -++#include "libbluray/bluray.h" -++ -++#if defined(_WIN32) -++#include -++#define sleep(x) Sleep(x) -++#endif -++ -++static void _usage(void) { -++ printf("Usage: [path to disc] [starting object]\n"); -++} -++ -++int main(int argc, char** argv) -++{ -++ if (argc < 3) { -++ _usage(); -++ return 0; -++ } -++ -++ printf("%s %s\n", argv[1], argv[2]); -++ -++ BLURAY* bd = bd_open(argv[1], NULL); -++ -++ bd_get_titles(bd, TITLES_ALL, 0); -++ -++ if (!bd_start_bdj(bd, argv[2])) { -++ printf("Failed to start BD-J application.\n"); -++ } else { -++ while (1) { sleep(20); } -++ bd_stop_bdj(bd); -++ } -++ -++ bd_close(bd); -++ -++ return 0; -++} -+diff --git a/src/devtools/bdjo_dump.c b/src/devtools/bdjo_dump.c -+new file mode 100644 -+index 0000000..c9c8141 -+--- /dev/null -++++ b/src/devtools/bdjo_dump.c -+@@ -0,0 +1,206 @@ -++/* -++ * This file is part of libbluray -++ * Copyright (C) 2014 Petri Hintukainen -++ * -++ * This library is free software; you can redistribute it and/or -++ * modify it under the terms of the GNU Lesser General Public -++ * License as published by the Free Software Foundation; either -++ * version 2.1 of the License, or (at your option) any later version. -++ * -++ * This library is distributed in the hope that it will be useful, -++ * but WITHOUT ANY WARRANTY; without even the implied warranty of -++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -++ * Lesser General Public License for more details. -++ * -++ * You should have received a copy of the GNU Lesser General Public -++ * License along with this library. If not, see -++ * . -++ */ -++ -++#include "libbluray/bluray.h" -++#include "libbluray/bdj/bdjo_data.h" -++ -++#include -++#include -++ -++static const char *_yes_no(int i) -++{ -++ return i > 0 ? "yes" : i < 0 ? "unknown" : "no"; -++} -++ -++static const char *_binding_str(int i) -++{ -++ switch (i) { -++ case 0: return "unbound"; -++ case 1: return "disc bound"; -++ case 3: return "title bound"; -++ default: return "???"; -++ } -++} -++ -++static const char *_visibility_str(int i) -++{ -++ switch (i) { -++ case 0: return "none"; -++ case 1: return "applications"; -++ case 2: return "user"; -++ default: return "???"; -++ } -++} -++ -++static void _terminal_info_print(const BDJO_TERMINAL_INFO *p) -++{ -++ printf("Terminal Info:\n"); -++ printf(" Default AWT font : %s\n", p->default_font); -++ printf(" initial HaVi config : %d\n", p->initial_havi_config_id); -++ printf(" Menu call mask : %d\n", p->menu_call_mask); -++ printf(" Title search mask : %d\n", p->menu_call_mask); -++} -++ -++static void _app_cache_item_print(const BDJO_APP_CACHE_ITEM *p) -++{ -++ printf(" %3.3s: %s%s\n", -++ p->lang_code, p->ref_to_name, -++ p->type == 1 ? ".jar" : p->type == 2 ? "/" : " (unknown type)"); -++} -++ -++static void _app_cache_info_print(const BDJO_APP_CACHE_INFO *p) -++{ -++ unsigned ii; -++ -++ printf("Application cache info:\n"); -++ for (ii = 0; ii < p->num_item; ii++) { -++ _app_cache_item_print(&p->item[ii]); -++ } -++} -++ -++static void _accessible_playlists_print(const BDJO_ACCESSIBLE_PLAYLISTS *p) -++{ -++ unsigned ii; -++ -++ printf("Accessible playlists:\n"); -++ printf(" Access to all : %s\n", _yes_no(p->access_to_all_flag)); -++ printf(" Autostart first : %s\n", _yes_no(p->autostart_first_playlist_flag)); -++ -++ if (p->num_pl) { -++ printf(" Playlists : %d\n", p->num_pl); -++ for (ii = 0; ii < p->num_pl; ii++) { -++ printf(" %s.mpls\n", p->pl[ii].name); -++ } -++ } -++} -++ -++static void _app_profile_print(BDJO_APP_PROFILE *p) -++{ -++ printf(" Profile %d Version %d.%d.%d\n", -++ p->profile_number, p->major_version, p->minor_version, p->micro_version); -++} -++ -++static void _app_print(const BDJO_APP *p) -++{ -++ unsigned ii; -++ -++ printf(" Control code: : %d (%s)\n", p->control_code, -++ p->control_code == 1 ? "autostart" : p->control_code == 2 ? "present" : "???"); -++ printf(" Type : %d (%s)\n", p->type, -++ p->type == 1 ? "BD-J App" : "???"); -++ printf(" Organization ID : %08X\n", p->org_id); -++ printf(" Application ID : %04X\n", p->app_id); -++ printf(" Priority : %d\n", p->priority); -++ printf(" Binding : %d (%s)\n", p->binding, _binding_str(p->binding)); -++ printf(" Visibility : %d (%s)\n", p->visibility, _visibility_str(p->visibility)); -++ -++ if (p->num_profile) { -++ printf(" Profiles:\n"); -++ for (ii = 0; ii < p->num_profile; ii++) { -++ _app_profile_print(&p->profile[ii]); -++ } -++ } -++ -++ if (p->num_name) { -++ printf(" Names:\n"); -++ for (ii = 0; ii < p->num_name; ii++) { -++ printf(" %s: %s\n", p->name[ii].lang, p->name[ii].name); -++ } -++ } -++ -++ printf(" Base directory : %s\n", p->base_dir); -++ printf(" Icon locator : %s\n", p->icon_locator); -++ printf(" Icon flags : 0x%04x\n", p->icon_flags); -++ printf(" Classpath extension : %s\n", p->classpath_extension); -++ printf(" Initial class : %s\n", p->initial_class); -++ printf(" Parameters : "); -++ for (ii = 0; ii < p->num_param; ii++) { -++ printf("%s ", p->param[ii].param); -++ } -++ printf("\n"); -++} -++ -++static void _app_management_table_print(const BDJO_APP_MANAGEMENT_TABLE *p) -++{ -++ unsigned ii; -++ -++ for (ii = 0; ii < p->num_app; ii++) { -++ printf("Application %u:\n", ii); -++ _app_print(&p->app[ii]); -++ } -++} -++ -++static void _key_interest_table_print(const BDJO_KEY_INTEREST_TABLE *p) -++{ -++ unsigned int v; -++ memcpy(&v, p, sizeof(unsigned int)); -++ if (v) { -++ printf("Key interest table:\n"); -++ printf(" %s%s%s%s%s%s%s%s%s%s%s\n", -++ p->vk_play ? "VK_PLAY " : "", -++ p->vk_stop ? "VK_STOP " : "", -++ p->vk_ffw ? "VK_FFW " : "", -++ p->vk_rew ? "VK_REW " : "", -++ p->vk_track_next ? "VK_TRACK_NEXT " : "", -++ p->vk_track_prev ? "VK_TRACK_PREV " : "", -++ p->vk_pause ? "VK_PAUSE " : "", -++ p->vk_still_off ? "VK_STILL_OFF " : "", -++ p->vk_sec_audio_ena_dis ? "VK_SEC_AUDIO " : "", -++ p->vk_sec_video_ena_dis ? "VK_SEC_VIDEO " : "", -++ p->pg_textst_ena_dis ? "VK_PG_TEXTST " : ""); -++ } -++} -++ -++static void _file_access_info_print(const BDJO_FILE_ACCESS_INFO *p) -++{ -++ printf("File access info:\n %s\n", p->path); -++} -++ -++static void _bdjo_print(const BDJO *p) -++{ -++ _terminal_info_print(&p->terminal_info); -++ _app_cache_info_print(&p->app_cache_info); -++ _accessible_playlists_print(&p->accessible_playlists); -++ _app_management_table_print(&p->app_table); -++ _key_interest_table_print(&p->key_interest_table); -++ _file_access_info_print(&p->file_access_info); -++} -++ -++int main(int argc, const char *argv[]) -++{ -++ if (argc < 2) { -++ fprintf(stderr, "usage: %s \n", argv[0]); -++ return 1; -++ } -++ -++ int cnt; -++ for (cnt = 1; cnt < argc; cnt++) { -++ -++ printf("%s\n", argv[cnt]); -++ -++ BDJO *bdjo = bd_read_bdjo(argv[cnt]); -++ if (bdjo) { -++ _bdjo_print(bdjo); -++ bd_free_bdjo(bdjo); -++ } -++ printf("\n"); -++ } -++ -++ return 0; -++} -+diff --git a/src/devtools/clpi_dump.c b/src/devtools/clpi_dump.c -+new file mode 100644 -+index 0000000..bd64783 -+--- /dev/null -++++ b/src/devtools/clpi_dump.c -+@@ -0,0 +1,487 @@ -++/* -++ * This file is part of libbluray -++ * Copyright (C) 2009-2010 John Stebbins -++ * Copyright (C) 2012-2013 Petri Hintukainen -++ * -++ * This library is free software; you can redistribute it and/or -++ * modify it under the terms of the GNU Lesser General Public -++ * License as published by the Free Software Foundation; either -++ * version 2.1 of the License, or (at your option) any later version. -++ * -++ * This library is distributed in the hope that it will be useful, -++ * but WITHOUT ANY WARRANTY; without even the implied warranty of -++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -++ * Lesser General Public License for more details. -++ * -++ * You should have received a copy of the GNU Lesser General Public -++ * License along with this library. If not, see -++ * . -++ */ -++ -++#include -++#include -++#include -++#include -++ -++#include "libbluray/bdnav/clpi_data.h" -++#include "libbluray/bluray.h" -++ -++#include "util.h" -++ -++static int verbose; -++ -++typedef struct { -++ int value; -++ const char *str; -++} VALUE_MAP; -++ -++static inline const char* -++_lookup_str(const VALUE_MAP *map, int val) -++{ -++ int ii; -++ -++ for (ii = 0; map[ii].str; ii++) { -++ if (val == map[ii].value) { -++ return map[ii].str; -++ } -++ } -++ return "?"; -++} -++ -++const VALUE_MAP codec_map[] = { -++ {0x01, "MPEG-1 Video"}, -++ {0x02, "MPEG-2 Video"}, -++ {0x03, "MPEG-1 Audio"}, -++ {0x04, "MPEG-2 Audio"}, -++ {0x80, "LPCM"}, -++ {0x81, "AC-3"}, -++ {0x82, "DTS"}, -++ {0x83, "TrueHD"}, -++ {0x84, "AC-3 Plus"}, -++ {0x85, "DTS-HD"}, -++ {0x86, "DTS-HD Master"}, -++ {0xa1, "AC-3 Plus for secondary audio"}, -++ {0xa2, "DTS-HD for secondary audio"}, -++ {0xea, "VC-1"}, -++ {0x1b, "H.264"}, -++ {0x20, "H.264 MVC dep."}, -++ {0x90, "Presentation Graphics"}, -++ {0x91, "Presentation Graphics"}, -++ {0x92, "Interactive Graphics"}, -++ {0, NULL} -++}; -++ -++const VALUE_MAP video_format_map[] = { -++ {0, "Reserved"}, -++ {1, "480i"}, -++ {2, "576i"}, -++ {3, "480p"}, -++ {4, "1080i"}, -++ {5, "720p"}, -++ {6, "1080p"}, -++ {7, "576p"}, -++ {0, NULL} -++}; -++ -++const VALUE_MAP video_rate_map[] = { -++ {0, "Reserved1"}, -++ {1, "23.976"}, -++ {2, "24"}, -++ {3, "25"}, -++ {4, "29.97"}, -++ {5, "Reserved2"}, -++ {6, "50"}, -++ {7, "59.94"}, -++ {0, NULL} -++}; -++ -++const VALUE_MAP video_aspect_map[] = { -++ {0, "Reserved1"}, -++ {1, "Reserved2"}, -++ {2, "4:3"}, -++ {3, "16:9"}, -++ {0, NULL} -++}; -++ -++const VALUE_MAP audio_format_map[] = { -++ {0, "Reserved1"}, -++ {1, "Mono"}, -++ {2, "Reserved2"}, -++ {3, "Stereo"}, -++ {4, "Reserved3"}, -++ {5, "Reserved4"}, -++ {6, "Multi Channel"}, -++ {12, "Combo"}, -++ {0, NULL} -++}; -++ -++const VALUE_MAP audio_rate_map[] = { -++ {0, "Reserved1"}, -++ {1, "48 Khz"}, -++ {2, "Reserved2"}, -++ {3, "Reserved3"}, -++ {4, "96 Khz"}, -++ {5, "192 Khz"}, -++ {12, "48/192 Khz"}, -++ {14, "48/96 Khz"}, -++ {0, NULL} -++}; -++ -++const VALUE_MAP application_type_map[] = { -++ {1, "Main TS for a main-path of Movie"}, -++ {2, "Main TS for a main-path of Time based slide show"}, -++ {3, "Main TS for a main-path of Browsable slide show"}, -++ {4, "Sub TS for a sub-path of Browsable slide show"}, -++ {5, "Sub TS for a sub-path of Interactive Graphics menu"}, -++ {6, "Sub TS for a sub-path of Text subtitle"}, -++ {7, "Sub TS for a sub-path of one or more elementary streams path"}, -++ {0, NULL}, -++}; -++ -++static void -++_show_stream(CLPI_PROG_STREAM *ss, int level) -++{ -++ indent_printf(level, "Codec (%04x): %s", ss->coding_type, -++ _lookup_str(codec_map, ss->coding_type)); -++ indent_printf(level, "PID: %04x", ss->pid); -++ switch (ss->coding_type) { -++ case 0x01: -++ case 0x02: -++ case 0xea: -++ case 0x1b: -++ case 0x20: -++ indent_printf(level, "Format %02x: %s", ss->format, -++ _lookup_str(video_format_map, ss->format)); -++ indent_printf(level, "Rate %02x: %s", ss->rate, -++ _lookup_str(video_rate_map, ss->rate)); -++ indent_printf(level, "Aspect %02x: %s", ss->aspect, -++ _lookup_str(video_aspect_map, ss->aspect)); -++ indent_printf(level, "oc_flag %02x", ss->oc_flag); -++ break; -++ -++ case 0x03: -++ case 0x04: -++ case 0x80: -++ case 0x81: -++ case 0x82: -++ case 0x83: -++ case 0x84: -++ case 0x85: -++ case 0x86: -++ case 0xa1: -++ case 0xa2: -++ indent_printf(level, "Format %02x: %s", ss->format, -++ _lookup_str(audio_format_map, ss->format)); -++ indent_printf(level, "Rate %02x: %s", ss->rate, -++ _lookup_str(audio_rate_map, ss->rate)); -++ indent_printf(level, "Language: %s", ss->lang); -++ break; -++ -++ case 0x90: -++ case 0x91: -++ case 0xa0: -++ indent_printf(level, "Language: %s", ss->lang); -++ break; -++ -++ case 0x92: -++ indent_printf(level, "Char Code: %02x", ss->char_code); -++ indent_printf(level, "Language: %s", ss->lang); -++ break; -++ -++ default: -++ fprintf(stderr, "unrecognized coding type %02x\n", ss->coding_type); -++ break; -++ }; -++} -++ -++static void -++_show_clip_info(CLPI_CL *cl, int level) -++{ -++ CLPI_CLIP_INFO *ci = &cl->clip; -++ int ii; -++ -++ indent_printf(level, "Clip Info"); -++ indent_printf(level+1, "Clip Stream Type: %02x", ci->clip_stream_type); -++ indent_printf(level+1, "Clip Application Type (%02x): %s", -++ ci->application_type, _lookup_str(application_type_map, ci->application_type)); -++ indent_printf(level+1, "is_ATC_delta: %s", ci->is_atc_delta ? "True" : "False"); -++ indent_printf(level+1, "ATC delta count: %d", ci->atc_delta_count); -++ indent_printf(level+1, "TS Recording Rate: %u", ci->ts_recording_rate); -++ indent_printf(level+1, "Number Source Packets: %u", ci->num_source_packets); -++ // Show ts type info -++ indent_printf(level+1, "TS Type Info"); -++ indent_printf(level+2, "Validity Flags %02x", ci->ts_type_info.validity); -++ indent_printf(level+2, "Format Id %s", ci->ts_type_info.format_id); -++ // Show cc5 thing -++ for (ii = 0; ii < ci->atc_delta_count; ii++) { -++ indent_printf(level+1, "ATC delta[ %d ]", ii); -++ indent_printf(level+2, "Delta %08x", ci->atc_delta[ii].delta); -++ indent_printf(level+2, "File Id %s", ci->atc_delta[ii].file_id); -++ indent_printf(level+2, "File Code %s", ci->atc_delta[ii].file_code); -++ } -++ // show fonts -++ if (cl->font_info.font_count) { -++ indent_printf(level+1, "Font files"); -++ for (ii = 0; ii < cl->font_info.font_count; ii++) { -++ indent_printf(level+2, "Font file %d: %s.otf", ii+1, cl->font_info.font[ii].file_id); -++ } -++ } -++ -++ printf("\n"); -++} -++ -++static void -++_show_seq_info(CLPI_SEQ_INFO *si, int level) -++{ -++ CLPI_ATC_SEQ *atc; -++ CLPI_STC_SEQ *stc; -++ int ii, jj; -++ -++ indent_printf(level, "Sequence Info"); -++ indent_printf(level+1, "Number ATC Sequences: %d", si->num_atc_seq); -++ for (ii = 0; ii < si->num_atc_seq; ii++) { -++ atc = &si->atc_seq[ii]; -++ indent_printf(level+1, "ATC Sequence %d", ii); -++ indent_printf(level+2, "SPN ATC Start: %u", atc->spn_atc_start); -++ indent_printf(level+2, "Offset STC Id: %d", atc->offset_stc_id); -++ indent_printf(level+2, "Number STC Sequences: %d", atc->num_stc_seq); -++ for (jj = 0; jj < atc->num_stc_seq; jj++) { -++ stc = &atc->stc_seq[jj]; -++ indent_printf(level+2, "ATC Sequence %d", jj); -++ indent_printf(level+3, "SPN STC Start: %u", stc->spn_stc_start); -++ indent_printf(level+3, "PCR PID: %04x", stc->pcr_pid); -++ indent_printf(level+3, "Presentation Start: %u", -++ stc->presentation_start_time); -++ indent_printf(level+3, "Presentation End: %u", -++ stc->presentation_end_time); -++ } -++ } -++} -++ -++static void -++_show_prog_info(CLPI_PROG_INFO *pi, int level) -++{ -++ CLPI_PROG *prog; -++ int ii, jj; -++ -++ indent_printf(level, "Program Info"); -++ indent_printf(level+1, "Number Programs: %d", pi->num_prog); -++ for (ii = 0; ii < pi->num_prog; ii++) { -++ prog = &pi->progs[ii]; -++ indent_printf(level+1, "Program %d", ii); -++ indent_printf(level+2, "SPN Program Sequence Start: %d", -++ prog->spn_program_sequence_start); -++ indent_printf(level+2, "Program Map PID: %d", prog->program_map_pid); -++ indent_printf(level+2, "Number Streams: %d", prog->num_streams); -++ indent_printf(level+2, "Number Groups: %d", prog->num_groups); -++ for (jj = 0; jj < prog->num_streams; jj++) { -++ indent_printf(level+2, "Stream %d", jj); -++ _show_stream(&prog->streams[jj], level+3); -++ } -++ } -++} -++ -++static void -++_show_extent_start(CLPI_EXTENT_START *es, int level) -++{ -++ unsigned int ii; -++ -++ indent_printf(level, "Extension data: Extent Start Point"); -++ -++ if (!es->num_point) { -++ indent_printf(level+1, "(no data)"); -++ -++ } else { -++ indent_printf(level+1, "Number of Start Points: %d", es->num_point); -++ -++ if (verbose) { -++ for (ii = 0; ii < es->num_point; ii++) { -++ indent_printf(level+1, "Extent %5d: SPN 0x%08X", ii, es->point[ii]); -++ } -++ } -++ } -++} -++ -++static void -++_show_cpi_info(CLPI_CPI *cpi, int level) -++{ -++ CLPI_EP_MAP_ENTRY *entry; -++ CLPI_EP_COARSE *coarse; -++ CLPI_EP_FINE *fine; -++ int ii, jj, kk; -++ -++ indent_printf(level, "CPI"); -++ indent_printf(level+1, "Number Stream PID: %d", cpi->num_stream_pid); -++ for (ii = 0; ii < cpi->num_stream_pid; ii++) { -++ entry = &cpi->entry[ii]; -++ indent_printf(level+1, "Stream: %d", ii); -++ indent_printf(level+2, "PID: %04x", entry->pid); -++ indent_printf(level+2, "EP Stream Type: %d", entry->ep_stream_type); -++ indent_printf(level+2, "Number EP Coarse: %d", entry->num_ep_coarse); -++ indent_printf(level+2, "Number EP Fine: %d", entry->num_ep_fine); -++ indent_printf(level+2, "EP Map Start: %d", -++ entry->ep_map_stream_start_addr); -++ for (jj = 0; jj < entry->num_ep_coarse; jj++) { -++ coarse = &entry->coarse[jj]; -++ indent_printf(level+2, "Coarse: %d", jj); -++ indent_printf(level+3, "Ref EP Fine: %d", coarse->ref_ep_fine_id); -++ indent_printf(level+3, "PTS EP: %d", coarse->pts_ep); -++ indent_printf(level+3, "SPN EP: %d", coarse->spn_ep); -++ } -++ for (jj = 0; jj < entry->num_ep_fine; jj++) { -++ fine = &entry->fine[jj]; -++ indent_printf(level+2, "Fine: %d", jj); -++ indent_printf(level+3, "Angle Change Point: %s", -++ fine->is_angle_change_point ? "True":"False"); -++ indent_printf(level+3, "I End Offset: %d", -++ fine->i_end_position_offset); -++ indent_printf(level+3, "PTS EP: %d", fine->pts_ep); -++ indent_printf(level+3, "SPN EP: %d", fine->spn_ep); -++ } -++ if (verbose) { -++ uint64_t pts; -++ uint32_t spn; -++ -++ indent_printf(level+2, "PTS - SPN Map"); -++ for (jj = 0; jj < entry->num_ep_coarse; jj++) { -++ int start, end; -++ -++ indent_printf(level+3, "Coarse: %d", jj); -++ coarse = &entry->coarse[jj]; -++ start = coarse->ref_ep_fine_id; -++ if (jj < entry->num_ep_coarse - 1) { -++ end = entry->coarse[jj+1].ref_ep_fine_id; -++ } else { -++ end = entry->num_ep_fine; -++ } -++ for (kk = start; kk < end; kk++) { -++ fine = &entry->fine[kk]; -++ pts = ((uint64_t) (coarse->pts_ep & ~0x01) << 19) + -++ ((uint64_t)fine->pts_ep << 9); -++ spn = (coarse->spn_ep & ~0x1FFFF) + fine->spn_ep; -++ indent_printf(level+4, "PTS %8"PRIu64"/%8"PRIu64" -- SPN %u", -++ pts, pts >> 1, spn); -++ } -++ } -++ } -++ } -++} -++ -++ -++static void -++_usage(char *cmd) -++{ -++ fprintf(stderr, -++"Usage: %s -vcspi [ ...]\n" -++"With no options, produces no output (not very useful)\n" -++"Options:\n" -++" v - Verbose output.\n" -++" c - Shows the Clip Info structure\n" -++" s - Shows the Sequence Info structure\n" -++" p - Shows the Program Info structure\n" -++" i - Shows the CPI. PTS to SPN map\n" -++" e - Shows Extent Start Table\n" -++, cmd); -++ -++ exit(EXIT_FAILURE); -++} -++ -++#define OPTS "vcspie" -++ -++int -++main(int argc, char *argv[]) -++{ -++ CLPI_CL *cl; -++ int opt; -++ int opt_clip_info = 0, opt_seq_info = 0, opt_prog_info = 0; -++ int opt_cpi_info = 0, opt_extent_start = 0; -++ int ii; -++ -++ do { -++ opt = getopt(argc, argv, OPTS); -++ switch (opt) { -++ case -1: break; -++ -++ case 'v': -++ verbose = 1; -++ break; -++ -++ case 's': -++ opt_seq_info = 1; -++ break; -++ -++ case 'i': -++ opt_cpi_info = 1; -++ break; -++ -++ case 'c': -++ opt_clip_info = 1; -++ break; -++ -++ case 'p': -++ opt_prog_info = 1; -++ break; -++ -++ case 'e': -++ opt_extent_start = 1; -++ break; -++ -++ default: -++ _usage(argv[0]); -++ break; -++ } -++ } while (opt != -1); -++ -++ if (optind >= argc) { -++ _usage(argv[0]); -++ } -++ -++ for (ii = optind; ii < argc; ii++) { -++ cl = bd_read_clpi(argv[ii]); -++ if (cl == NULL) { -++ fprintf(stderr, "Parsing %s failed\n", argv[ii]); -++ continue; -++ } -++ if (opt_clip_info) { -++ // Show clip info -++ _show_clip_info(cl, 1); -++ } -++ if (opt_seq_info) { -++ // Show sequence info -++ _show_seq_info(&cl->sequence, 1); -++ } -++ if (opt_prog_info) { -++ // Show program info -++ _show_prog_info(&cl->program, 1); -++ } -++ if (opt_cpi_info) { -++ // Show cpi -++ _show_cpi_info(&cl->cpi, 1); -++ } -++ -++ if (opt_prog_info) { -++ if (cl->program_ss.num_prog) { -++ printf("\n"); -++ indent_printf(1, "Extension: Program Info SS"); -++ _show_prog_info(&cl->program_ss, 1); -++ } -++ } -++ if (opt_cpi_info) { -++ if (cl->program_ss.num_prog) { -++ printf("\n"); -++ indent_printf(1, "Extension: CPI SS"); -++ _show_cpi_info(&cl->cpi_ss, 1); -++ } -++ } -++ if (opt_extent_start) { -++ // Show extent start point -++ if (cl->extent_start.num_point > 0) { -++ _show_extent_start(&cl->extent_start, 1); -++ } -++ } -++ -++ bd_free_clpi(cl); -++ } -++ return 0; -++} -++ -+diff --git a/src/devtools/hdmv_test.c b/src/devtools/hdmv_test.c -+new file mode 100644 -+index 0000000..585ed70 -+--- /dev/null -++++ b/src/devtools/hdmv_test.c -+@@ -0,0 +1,257 @@ -++/* -++ * This file is part of libbluray -++ * Copyright (C) 2010 hpi1 -++ * -++ * This library is free software; you can redistribute it and/or -++ * modify it under the terms of the GNU Lesser General Public -++ * License as published by the Free Software Foundation; either -++ * version 2.1 of the License, or (at your option) any later version. -++ * -++ * This library is distributed in the hope that it will be useful, -++ * but WITHOUT ANY WARRANTY; without even the implied warranty of -++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -++ * Lesser General Public License for more details. -++ * -++ * You should have received a copy of the GNU Lesser General Public -++ * License along with this library. If not, see -++ * . -++ */ -++ -++#include -++#include -++#include -++#include -++ -++#include "util/log_control.h" -++#include "libbluray/bluray.h" -++ -++static void _print_event(BD_EVENT *ev) -++{ -++ switch (ev->event) { -++ case BD_EVENT_NONE: -++ break; -++ case BD_EVENT_ERROR: -++ printf("EVENT_ERROR:\t%d\n", ev->param); -++ break; -++ case BD_EVENT_READ_ERROR: -++ printf("EVENT_READ_ERROR:\t%d\n", ev->param); -++ break; -++ case BD_EVENT_ENCRYPTED: -++ printf("EVENT_ENCRYPTED:\t%d\n", ev->param); -++ break; -++ -++ /* current playback position */ -++ -++ case BD_EVENT_ANGLE: -++ printf("EVENT_ANGLE:\t%d\n", ev->param); -++ break; -++ case BD_EVENT_TITLE: -++ printf("EVENT_TITLE:\t%d\n", ev->param); -++ break; -++ case BD_EVENT_PLAYLIST: -++ printf("EVENT_PLAYLIST:\t%d\n", ev->param); -++ break; -++ case BD_EVENT_PLAYITEM: -++ printf("EVENT_PLAYITEM:\t%d\n", ev->param); -++ break; -++ case BD_EVENT_CHAPTER: -++ printf("EVENT_CHAPTER:\t%d\n", ev->param); -++ break; -++ -++ /* */ -++ -++ case BD_EVENT_STILL: -++ printf("EVENT_STILL:\t%d\n", ev->param); -++ break; -++ -++ case BD_EVENT_SEEK: -++ printf("EVENT_SEEK:\t%d\n", ev->param); -++ break; -++ -++ case BD_EVENT_STILL_TIME: -++ if (ev->param) { -++ printf("EVENT_STILL_TIME:\t%d\n", ev->param); -++ } else { -++ printf("EVENT_STILL_TIME:\tinfinite\n"); -++ } -++ break; -++ -++ /* stream selection */ -++ -++ case BD_EVENT_AUDIO_STREAM: -++ printf("EVENT_AUDIO_STREAM:\t%d\n", ev->param); -++ break; -++ case BD_EVENT_IG_STREAM: -++ printf("EVENT_IG_STREAM:\t%d\n", ev->param); -++ break; -++ case BD_EVENT_PG_TEXTST_STREAM: -++ printf("EVENT_PG_TEXTST_STREAM:\t%d\n", ev->param); -++ break; -++ case BD_EVENT_SECONDARY_AUDIO_STREAM: -++ printf("EVENT_SECONDARY_AUDIO_STREAM:\t%d\n", ev->param); -++ break; -++ case BD_EVENT_SECONDARY_VIDEO_STREAM: -++ printf("EVENT_SECONDARY_VIDEO_STREAM:\t%d\n", ev->param); -++ break; -++ -++ case BD_EVENT_PG_TEXTST: -++ printf("EVENT_PG_TEXTST:\t%s\n", ev->param ? "enable" : "disable"); -++ break; -++ case BD_EVENT_SECONDARY_AUDIO: -++ printf("EVENT_SECONDARY_AUDIO:\t%s\n", ev->param ? "enable" : "disable"); -++ break; -++ case BD_EVENT_SECONDARY_VIDEO: -++ printf("EVENT_SECONDARY_VIDEO:\t%s\n", ev->param ? "enable" : "disable"); -++ break; -++ case BD_EVENT_SECONDARY_VIDEO_SIZE: -++ printf("EVENT_SECONDARY_VIDEO_SIZE:\t%s\n", ev->param==0 ? "PIP" : "fullscreen"); -++ break; -++ -++ default: -++ printf("UNKNOWN EVENT %d:\t%d\n", ev->event, ev->param); -++ break; -++ } -++ -++ fflush(stdout); -++} -++ -++static void _read_to_eof(BLURAY *bd) -++{ -++ BD_EVENT ev; -++ int bytes; -++ uint64_t total = 0; -++ uint8_t buf[6144]; -++ -++ bd_seek(bd, bd_get_title_size(bd) - 6144); -++ -++ do { -++ bytes = bd_read_ext(bd, buf, 6144, &ev); -++ total += bytes < 0 ? 0 : bytes; -++ _print_event(&ev); -++ } while (bytes > 0); -++ -++ printf("_read_to_eof(): read %"PRIu64" bytes\n", total); -++} -++ -++static void _print_events(BLURAY *bd) -++{ -++ BD_EVENT ev; -++ -++ do { -++ bd_read_ext(bd, NULL, 0, &ev); -++ _print_event(&ev); -++ } while (ev.event != BD_EVENT_NONE && ev.event != BD_EVENT_ERROR); -++} -++ -++static void _play_pl(BLURAY *bd) -++{ -++ printf("Playing playlist\n"); -++ -++ fflush(stdout); -++ _read_to_eof(bd); -++ -++ printf("Playing playlist done\n\n"); -++ -++ _print_events(bd); -++ -++ printf("\n"); -++} -++ -++int main(int argc, char *argv[]) -++{ -++ int title = -1; -++ int verbose = 0; -++ int args = 0; -++ -++ /* -++ * parse arguments -++ */ -++ -++ if (argc < 2) { -++ printf("\nUsage:\n %s [-v] [-t ] <media_path> [<keyfile_path>]\n\n", argv[0]); -++ return -1; -++ } -++ -++ if (!strcmp(argv[1+args], "-v")) { -++ verbose = 1; -++ args++; -++ } -++ -++ if (!strcmp(argv[1+args], "-t")) { -++ args++; -++ title = atoi(argv[1+args]); -++ args++; -++ printf("Requested title %d\n", title); -++ } -++ -++ if (verbose) { -++ printf("Enabling verbose debug\n"); -++ bd_set_debug_mask(bd_get_debug_mask() | DBG_HDMV | DBG_BLURAY); -++ } -++ -++ printf("\n"); -++ -++ /* -++ * open and setup -++ */ -++ -++ BLURAY *bd = bd_open(argv[1+args], argv[2+args]); -++ -++ if (!bd) { -++ printf("bd_open(\'%s\') failed\n", argv[1]); -++ return -1; -++ } -++ -++ bd_set_player_setting (bd, BLURAY_PLAYER_SETTING_PARENTAL, 99); -++ bd_set_player_setting_str(bd, BLURAY_PLAYER_SETTING_AUDIO_LANG, "eng"); -++ bd_set_player_setting_str(bd, BLURAY_PLAYER_SETTING_PG_LANG, "eng"); -++ bd_set_player_setting_str(bd, BLURAY_PLAYER_SETTING_MENU_LANG, "eng"); -++ bd_set_player_setting_str(bd, BLURAY_PLAYER_SETTING_COUNTRY_CODE, NULL); -++ -++ /* -++ * play -++ */ -++ -++ printf("Running first play movie object\n"); -++ -++ fflush(stdout); -++ bd_play(bd); -++ -++ _print_events(bd); -++ -++ printf("\n"); -++ -++ /* -++ * play title -++ */ -++ -++ if (title >= 0) { -++ printf("Playing title %d\n", title); -++ -++ fflush(stdout); -++ bd_play_title(bd, title); -++ -++ _print_events(bd); -++ -++ printf("\n"); -++ } -++ -++ /* -++ * play playlist -++ */ -++ -++ _play_pl(bd); -++ -++ _play_pl(bd); -++ -++ _play_pl(bd); -++ -++ /* -++ * clean up -++ */ -++ -++ bd_close(bd); -++ -++ return 0; -++} -++ -+diff --git a/src/devtools/mobj_dump.c b/src/devtools/mobj_dump.c -+new file mode 100644 -+index 0000000..3eaf9f4 -+--- /dev/null -++++ b/src/devtools/mobj_dump.c -+@@ -0,0 +1,83 @@ -++/* -++ * This file is part of libbluray -++ * Copyright (C) 2010 hpi1 -++ * -++ * This library is free software; you can redistribute it and/or -++ * modify it under the terms of the GNU Lesser General Public -++ * License as published by the Free Software Foundation; either -++ * version 2.1 of the License, or (at your option) any later version. -++ * -++ * This library is distributed in the hope that it will be useful, -++ * but WITHOUT ANY WARRANTY; without even the implied warranty of -++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -++ * Lesser General Public License for more details. -++ * -++ * You should have received a copy of the GNU Lesser General Public -++ * License along with this library. If not, see -++ * <http://www.gnu.org/licenses/>. -++ */ -++ -++#include "libbluray/bluray.h" -++ -++#include "libbluray/hdmv/mobj_data.h" -++#include "libbluray/hdmv/mobj_print.h" -++ -++#include <stdio.h> -++#include <string.h> -++ -++static void _mobj_print(MOBJ_OBJECTS *objects, int disasm) -++{ -++ int o, c; -++ -++ printf("Number of objects: %d\n", objects->num_objects); -++ -++ for (o = 0; o < objects->num_objects; o++) { -++ -++ printf("Object %d:\n" -++ " number of commands: %d\n" -++ " resume intention flag: %d\n" -++ " menu call mask: %d\n" -++ " title search mask: %d\n", -++ o, objects->objects[o].num_cmds, -++ objects->objects[o].resume_intention_flag, -++ objects->objects[o].menu_call_mask, -++ objects->objects[o].title_search_mask); -++ -++ if (disasm) { -++ printf(" program:\n"); -++ for (c = 0; c < objects->objects[o].num_cmds; c++) { -++ char buf[256]; -++ mobj_sprint_cmd(buf, &objects->objects[o].cmds[c]); -++ printf(" %04d: %s\n", c, buf); -++ } -++ } -++ } -++} -++ -++int main(int argc, const char *argv[]) -++{ -++ int disasm = 0; -++ MOBJ_OBJECTS *mobj = NULL; -++ -++ if (argc < 2) { -++ fprintf(stderr, -++ "usage: %s [-d] <file>\n" -++ "Options:\n" -++ " d disassemble object code\n", -++ argv[0]); -++ return 1; -++ } -++ if (argc > 2) { -++ disasm = !strcmp(argv[1], "-d"); -++ } -++ -++ mobj = bd_read_mobj(argv[argc-1]); -++ -++ if (mobj) { -++ _mobj_print(mobj, disasm); -++ -++ bd_free_mobj(mobj); -++ } -++ -++ return 0; -++} -+diff --git a/src/devtools/mpls_dump.c b/src/devtools/mpls_dump.c -+new file mode 100644 -+index 0000000..405b6a1 -+--- /dev/null -++++ b/src/devtools/mpls_dump.c -+@@ -0,0 +1,799 @@ -++/* -++ * This file is part of libbluray -++ * Copyright (C) 2009-2010 John Stebbins -++ * -++ * This library is free software; you can redistribute it and/or -++ * modify it under the terms of the GNU Lesser General Public -++ * License as published by the Free Software Foundation; either -++ * version 2.1 of the License, or (at your option) any later version. -++ * -++ * This library is distributed in the hope that it will be useful, -++ * but WITHOUT ANY WARRANTY; without even the implied warranty of -++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -++ * Lesser General Public License for more details. -++ * -++ * You should have received a copy of the GNU Lesser General Public -++ * License along with this library. If not, see -++ * <http://www.gnu.org/licenses/>. -++ */ -++ -++#include <sys/stat.h> -++#include <dirent.h> -++#include <stdio.h> -++#include <stdlib.h> -++#include <unistd.h> -++#include <string.h> -++#include <libgen.h> -++ -++#include "libbluray/bdnav/mpls_parse.h" -++#include "libbluray/bluray.h" -++ -++#include "util.h" -++ -++#ifdef _WIN32 -++# define DIR_SEP "\\" -++# define PLAYLIST_DIR "\\BDMV\\PLAYLIST" -++#else -++# define DIR_SEP "/" -++# define PLAYLIST_DIR "/BDMV/PLAYLIST" -++#endif -++ -++ -++static int verbose; -++ -++typedef struct { -++ int value; -++ const char *str; -++} VALUE_MAP; -++ -++const VALUE_MAP codec_map[] = { -++ {0x01, "MPEG-1 Video"}, -++ {0x02, "MPEG-2 Video"}, -++ {0x03, "MPEG-1 Audio"}, -++ {0x04, "MPEG-2 Audio"}, -++ {0x80, "LPCM"}, -++ {0x81, "AC-3"}, -++ {0x82, "DTS"}, -++ {0x83, "TrueHD"}, -++ {0x84, "AC-3 Plus"}, -++ {0x85, "DTS-HD"}, -++ {0x86, "DTS-HD Master"}, -++ {0xa1, "AC-3 Plus for secondary audio"}, -++ {0xa2, "DTS-HD for secondary audio"}, -++ {0xea, "VC-1"}, -++ {0x1b, "H.264"}, -++ {0x90, "Presentation Graphics"}, -++ {0x91, "Interactive Graphics"}, -++ {0x92, "Text Subtitle"}, -++ {0, NULL} -++}; -++ -++const VALUE_MAP video_format_map[] = { -++ {0, "Reserved"}, -++ {1, "480i"}, -++ {2, "576i"}, -++ {3, "480p"}, -++ {4, "1080i"}, -++ {5, "720p"}, -++ {6, "1080p"}, -++ {7, "576p"}, -++ {0, NULL} -++}; -++ -++const VALUE_MAP video_rate_map[] = { -++ {0, "Reserved1"}, -++ {1, "23.976"}, -++ {2, "24"}, -++ {3, "25"}, -++ {4, "29.97"}, -++ {5, "Reserved2"}, -++ {6, "50"}, -++ {7, "59.94"}, -++ {0, NULL} -++}; -++ -++const VALUE_MAP audio_format_map[] = { -++ {0, "Reserved1"}, -++ {1, "Mono"}, -++ {2, "Reserved2"}, -++ {3, "Stereo"}, -++ {4, "Reserved3"}, -++ {5, "Reserved4"}, -++ {6, "Multi Channel"}, -++ {12, "Combo"}, -++ {0, NULL} -++}; -++ -++const VALUE_MAP audio_rate_map[] = { -++ {0, "Reserved1"}, -++ {1, "48 Khz"}, -++ {2, "Reserved2"}, -++ {3, "Reserved3"}, -++ {4, "96 Khz"}, -++ {5, "192 Khz"}, -++ {12, "48/192 Khz"}, -++ {14, "48/96 Khz"}, -++ {0, NULL} -++}; -++ -++const VALUE_MAP subpath_type_map[] = { -++ {2, "Primary audio of the Browsable slideshow"}, -++ {3, "Interactive Graphics presentation menu"}, -++ {4, "Text Subtitle"}, -++ {5, "Out-of-mux Synchronous elementary streams"}, -++ {6, "Out-of-mux Asynchronous Picture-in-Picture presentation"}, -++ {7, "In-mux Synchronous Picture-in-Picture presentation"}, -++ {8, "SS Video"}, -++ {0,NULL} -++}; -++ -++const VALUE_MAP playback_type_map[] = { -++ {1, "Sequential"}, -++ {2, "Random"}, -++ {3, "Shuffle"}, -++ {0, NULL} -++}; -++ -++const VALUE_MAP connection_type_map[] = { -++ {1, "Non-seamless"}, -++ {5, "Seamless"}, -++ {6, "Seamless"}, -++ {0, NULL} -++}; -++ -++static const char* -++_lookup_str(const VALUE_MAP *map, int val) -++{ -++ int ii; -++ -++ for (ii = 0; map[ii].str; ii++) { -++ if (val == map[ii].value) { -++ return map[ii].str; -++ } -++ } -++ return "?"; -++} -++ -++static char * -++_mk_path(const char *base, const char *sub) -++{ -++ size_t n1 = strlen(base); -++ size_t n2 = strlen(sub); -++ char *result = (char*)malloc(n1 + n2 + strlen(DIR_SEP) + 1); -++ strcpy(result, base); -++ strcat(result, DIR_SEP); -++ strcat(result, sub); -++ -++ return result; -++} -++ -++static void -++_show_stream(MPLS_STREAM *ss, int level) -++{ -++ indent_printf(level, "Codec (%04x): %s", ss->coding_type, -++ _lookup_str(codec_map, ss->coding_type)); -++ switch (ss->stream_type) { -++ case 1: -++ indent_printf(level, "PID: %04x", ss->pid); -++ break; -++ -++ case 2: -++ case 4: -++ indent_printf(level, "SubPath Id: %02x", ss->subpath_id); -++ indent_printf(level, "SubClip Id: %02x", ss->subclip_id); -++ indent_printf(level, "PID: %04x", ss->pid); -++ break; -++ -++ case 3: -++ indent_printf(level, "SubPath Id: %02x", ss->subpath_id); -++ indent_printf(level, "PID: %04x", ss->pid); -++ break; -++ -++ default: -++ fprintf(stderr, "unrecognized stream type %02x\n", ss->stream_type); -++ break; -++ }; -++ -++ switch (ss->coding_type) { -++ case 0x01: -++ case 0x02: -++ case 0xea: -++ case 0x1b: -++ indent_printf(level, "Format %02x: %s", ss->format, -++ _lookup_str(video_format_map, ss->format)); -++ indent_printf(level, "Rate %02x: %s", ss->rate, -++ _lookup_str(video_rate_map, ss->rate)); -++ break; -++ -++ case 0x03: -++ case 0x04: -++ case 0x80: -++ case 0x81: -++ case 0x82: -++ case 0x83: -++ case 0x84: -++ case 0x85: -++ case 0x86: -++ case 0xa1: -++ case 0xa2: -++ indent_printf(level, "Format %02x: %s", ss->format, -++ _lookup_str(audio_format_map, ss->format)); -++ indent_printf(level, "Rate %02x: %s", ss->rate, -++ _lookup_str(audio_rate_map, ss->rate)); -++ indent_printf(level, "Language: %s", ss->lang); -++ break; -++ -++ case 0x90: -++ case 0x91: -++ indent_printf(level, "Language: %s", ss->lang); -++ break; -++ -++ case 0x92: -++ indent_printf(level, "Char Code: %02x", ss->char_code); -++ indent_printf(level, "Language: %s", ss->lang); -++ break; -++ -++ default: -++ fprintf(stderr, "unrecognized coding type %02x\n", ss->coding_type); -++ break; -++ }; -++} -++ -++static void -++_show_details(MPLS_PL *pl, int level) -++{ -++ int ii, jj, kk; -++ -++ for (ii = 0; ii < pl->list_count; ii++) { -++ MPLS_PI *pi; -++ -++ pi = &pl->play_item[ii]; -++ indent_printf(level, "Clip Id %s", pi->clip[0].clip_id); -++ indent_printf(level+1, "Stc Id: %02x", pi->clip[0].stc_id); -++ indent_printf(level+1, "Connection Condition: %s (%02x)", -++ _lookup_str(connection_type_map, pi->connection_condition), -++ pi->connection_condition); -++ indent_printf(level+1, "In-Time: %d", pi->in_time); -++ indent_printf(level+1, "Out-Time: %d", pi->out_time); -++ if (pi->still_mode == 1) { -++ indent_printf(level+1, "Still time: %ds\n", pi->still_time); -++ } -++ if (pi->still_mode == 2) { -++ indent_printf(level+1, "Still time: infinite\n"); -++ } -++ if (pi->angle_count > 1) { -++ for (jj = 1; jj < pi->angle_count; jj++) { -++ indent_printf(level+1, "Angle %d:", jj); -++ indent_printf(level+2, "Clip Id %s", pi->clip[jj].clip_id); -++ indent_printf(level+2, "Stc Id: %02x", pi->clip[jj].stc_id); -++ } -++ } -++ for (jj = 0; jj < pi->stn.num_video; jj++) { -++ indent_printf(level+1, "Video Stream %d:", jj); -++ _show_stream(&pi->stn.video[jj], level + 2); -++ } -++ for (jj = 0; jj < pi->stn.num_audio; jj++) { -++ indent_printf(level+1, "Audio Stream %d:", jj); -++ _show_stream(&pi->stn.audio[jj], level + 2); -++ } -++ for (jj = 0; jj < pi->stn.num_ig; jj++) { -++ indent_printf(level+1, "Interactive Graphics Stream %d:", jj); -++ _show_stream(&pi->stn.ig[jj], level + 2); -++ } -++ for (jj = 0; jj < (pi->stn.num_pg + pi->stn.num_pip_pg); jj++) { -++ if (jj < pi->stn.num_pg) { -++ indent_printf(level+1, "Presentation Graphics Stream %d:", jj); -++ } else { -++ indent_printf(level+1, "PIP Presentation Graphics Stream %d:", jj); -++ } -++ _show_stream(&pi->stn.pg[jj], level + 2); -++ } -++ for (jj = 0; jj < pi->stn.num_secondary_video; jj++) { -++ indent_printf(level+1, "Secondary Video Stream %d:", jj); -++ _show_stream(&pi->stn.secondary_video[jj], level + 2); -++ for (kk = 0; kk < pi->stn.secondary_video[jj].sv_num_secondary_audio_ref; kk++) { -++ indent_printf(level+2, "Secondary Audio Ref %d: %d", kk,pi->stn.secondary_video[jj].sv_secondary_audio_ref[kk]); -++ } -++ for (kk = 0; kk < pi->stn.secondary_video[jj].sv_num_pip_pg_ref; kk++) { -++ indent_printf(level+2, "PIP Presentation Graphic Ref %d: %d", kk,pi->stn.secondary_video[jj].sv_pip_pg_ref[kk]); -++ } -++ } -++ for (jj = 0; jj < pi->stn.num_secondary_audio; jj++) { -++ indent_printf(level+1, "Secondary Audio Stream %d:", jj); -++ _show_stream(&pi->stn.secondary_audio[jj], level + 2); -++ for (kk = 0; kk < pi->stn.secondary_audio[jj].sa_num_primary_audio_ref; kk++) { -++ indent_printf(level+2, "Primary Audio Ref %d: %d", kk,pi->stn.secondary_audio[jj].sa_primary_audio_ref[kk]); -++ } -++ } -++ printf("\n"); -++ } -++} -++ -++static void -++_show_ai(MPLS_PL *pl, int level) -++{ -++ indent_printf(level, "Playback type: %s (%d)", -++ _lookup_str(playback_type_map, pl->app_info.playback_type), -++ pl->app_info.playback_type); -++ if (pl->app_info.playback_type == 2 || pl->app_info.playback_type == 3) { -++ indent_printf(level+1, "Playback count: %d", pl->app_info.playback_count); -++ } -++} -++ -++static void -++_show_marks(MPLS_PL *pl, int level) -++{ -++ int ii; -++ -++ indent_printf(level, "PlayMark Count %d", pl->mark_count); -++ for (ii = 0; ii < pl->mark_count; ii++) { -++ MPLS_PI *pi; -++ MPLS_PLM *plm; -++ int min; -++ double sec; -++ -++ plm = &pl->play_mark[ii]; -++ indent_printf(level, "PlayMark %d", ii); -++ indent_printf(level+1, "Type: %02x", plm->mark_type); -++ if (plm->play_item_ref < pl->list_count) { -++ pi = &pl->play_item[plm->play_item_ref]; -++ indent_printf(level+1, "PlayItem: %s", pi->clip[0].clip_id); -++ } else { -++ indent_printf(level+1, "PlayItem: Invalid reference"); -++ } -++ indent_printf(level+1, "Time (ticks): %u", plm->time); -++ min = plm->duration / (45000*60); -++ sec = (double)(plm->duration - min * 45000 * 60) / 45000; -++ indent_printf(level+1, "Duration (mm:ss.ms, ticks): %d:%.2f, %u", -++ min, sec, plm->duration); -++ printf("\n"); -++ } -++} -++ -++static void -++_show_clip_list(MPLS_PL *pl, int level) -++{ -++ int ii, jj; -++ -++ for (ii = 0; ii < pl->list_count; ii++) { -++ MPLS_PI *pi; -++ -++ pi = &pl->play_item[ii]; -++ if (verbose) { -++ uint32_t duration; -++ -++ duration = pi->out_time - pi->in_time; -++ indent_printf(level, "%s.m2ts -- Duration: %3d:%02d", -++ pi->clip[0].clip_id, -++ duration / (45000 * 60), (duration / 45000) % 60); -++ } else { -++ indent_printf(level, "%s.m2ts", pi->clip[0].clip_id); -++ } -++ if (pi->angle_count > 1) { -++ for (jj = 1; jj < pi->angle_count; jj++) { -++ indent_printf(level+1, "Angle %d: %s.m2ts", jj+1, pi->clip[jj].clip_id); -++ } -++ } -++ } -++ printf("\n"); -++} -++ -++static void -++_show_sub_path(MPLS_SUB *sub, int level) -++{ -++ int ii; -++ -++ indent_printf(level+1, "Type: %d (%s)", sub->type, _lookup_str(subpath_type_map, sub->type)); -++ indent_printf(level+1, "Repeat: %d", sub->is_repeat); -++ indent_printf(level+1, "Sub playitem count: %d", sub->sub_playitem_count); -++ -++ for (ii = 0; ii < sub->sub_playitem_count; ii++) { -++ MPLS_SUB_PI *pi; -++ -++ pi = &sub->sub_play_item[ii]; -++ -++ if (verbose) { -++ indent_printf(level+1, "Sub playitem %d", ii); -++ indent_printf(level+2, "Clip Id %s", pi->clip[0].clip_id); -++ indent_printf(level+2, "Multi clip: %d", pi->is_multi_clip); -++ indent_printf(level+2, "Clip count: %d", pi->clip_count); -++ indent_printf(level+2, "Connection Condition: %s (%02x)", -++ _lookup_str(connection_type_map, pi->connection_condition), -++ pi->connection_condition); -++ indent_printf(level+2, "In-Time: %d", pi->in_time); -++ indent_printf(level+2, "Out-Time: %d", pi->out_time); -++ indent_printf(level+2, "Sync playitem Id: %d", pi->sync_play_item_id); -++ indent_printf(level+2, "Sync PTS: %d", pi->sync_pts); -++ } else { -++ indent_printf(level+1, "%s.m2ts", pi->clip[0].clip_id); -++ } -++ } -++} -++ -++static void -++_show_pip_metadata_block(MPLS_PIP_METADATA *block, int level) -++{ -++ int ii; -++ -++ indent_printf(level, "Clip ref: %d", block->clip_ref); -++ indent_printf(level, "Secondary video ref: %d", block->secondary_video_ref); -++ indent_printf(level, "Timeline type: %d", block->timeline_type); -++ indent_printf(level, "Luma key flag: %d", block->luma_key_flag); -++ if (block->luma_key_flag) { -++ indent_printf(level, "Upper limit luma key: %d", block->upper_limit_luma_key); -++ } -++ indent_printf(level, "Trick play flag: %d", block->trick_play_flag); -++ -++ for (ii = 0; ii < block->data_count; ii++) { -++ indent_printf(level, "data block %d:", ii); -++ indent_printf(level+1, "Timestamp: %d", block->data[ii].time); -++ indent_printf(level+1, "Horizontal position %d", block->data[ii].xpos); -++ indent_printf(level+1, "Vertical position: %d", block->data[ii].ypos); -++ indent_printf(level+1, "Scaling factor: %d", block->data[ii].scale_factor); -++ } -++} -++ -++static void -++_show_pip_metadata(MPLS_PL *pl, int level) -++{ -++ int ii; -++ -++ for (ii = 0; ii < pl->ext_pip_data_count; ii++) { -++ MPLS_PIP_METADATA *data; -++ -++ data = &pl->ext_pip_data[ii]; -++ -++ indent_printf(level, "PiP metadata block %d:", ii); -++ _show_pip_metadata_block(data, level+1); -++ } -++} -++ -++static void -++_show_sub_paths(MPLS_PL *pl, int level) -++{ -++ int ss; -++ -++ for (ss = 0; ss < pl->sub_count; ss++) { -++ MPLS_SUB *sub; -++ -++ sub = &pl->sub_path[ss]; -++ -++ indent_printf(level, "Sub Path %d:", ss); -++ _show_sub_path(sub, level+1); -++ } -++} -++ -++static void -++_show_sub_paths_ss(MPLS_PL *pl, int level) -++{ -++ int ss; -++ -++ for (ss = 0; ss < pl->ext_sub_count; ss++) { -++ MPLS_SUB *sub; -++ -++ sub = &pl->ext_sub_path[ss]; -++ -++ indent_printf(level, "Extension Sub Path %d:", ss); -++ _show_sub_path(sub, level+1); -++ } -++} -++ -++static uint32_t -++_pl_duration(MPLS_PL *pl) -++{ -++ int ii; -++ uint32_t duration = 0; -++ MPLS_PI *pi; -++ -++ for (ii = 0; ii < pl->list_count; ii++) { -++ pi = &pl->play_item[ii]; -++ duration += pi->out_time - pi->in_time; -++ } -++ return duration; -++} -++ -++static int -++_filter_dup(MPLS_PL *pl_list[], int count, MPLS_PL *pl) -++{ -++ int ii, jj; -++ -++ for (ii = 0; ii < count; ii++) { -++ if (pl->list_count != pl_list[ii]->list_count || -++ _pl_duration(pl) != _pl_duration(pl_list[ii])) { -++ continue; -++ } -++ for (jj = 0; jj < pl->list_count; jj++) { -++ MPLS_PI *pi1, *pi2; -++ -++ pi1 = &pl->play_item[jj]; -++ pi2 = &pl_list[ii]->play_item[jj]; -++ -++ if (memcmp(pi1->clip[0].clip_id, pi2->clip[0].clip_id, 5) != 0 || -++ pi1->in_time != pi2->in_time || -++ pi1->out_time != pi2->out_time) { -++ break; -++ } -++ } -++ if (jj != pl->list_count) { -++ continue; -++ } -++ return 0; -++ } -++ return 1; -++} -++ -++static int -++_find_repeats(MPLS_PL *pl, const char *m2ts) -++{ -++ int ii, count = 0; -++ -++ for (ii = 0; ii < pl->list_count; ii++) { -++ MPLS_PI *pi; -++ -++ pi = &pl->play_item[ii]; -++ // Ignore titles with repeated segments -++ if (strcmp(pi->clip[0].clip_id, m2ts) == 0) { -++ count++; -++ } -++ } -++ return count; -++} -++ -++static int -++_filter_short(MPLS_PL *pl, unsigned int seconds) -++{ -++ // Ignore short playlists -++ if (_pl_duration(pl) / 45000 <= seconds) { -++ return 0; -++ } -++ return 1; -++} -++ -++static int -++_filter_repeats(MPLS_PL *pl, int repeats) -++{ -++ int ii; -++ -++ for (ii = 0; ii < pl->list_count; ii++) { -++ MPLS_PI *pi; -++ -++ pi = &pl->play_item[ii]; -++ // Ignore titles with repeated segments -++ if (_find_repeats(pl, pi->clip[0].clip_id) > repeats) { -++ return 0; -++ } -++ } -++ return 1; -++} -++ -++static int clip_list = 0, playlist_info = 0, chapter_marks = 0, sub_paths = 0, pip_metadata = 0; -++static int repeats = 0, seconds = 0, dups = 0; -++ -++static MPLS_PL* -++_process_file(char *name, MPLS_PL *pl_list[], int pl_count) -++{ -++ MPLS_PL *pl; -++ -++ pl = bd_read_mpls(name); -++ if (pl == NULL) { -++ fprintf(stderr, "Parse failed: %s\n", name); -++ return NULL; -++ } -++ if (seconds) { -++ if (!_filter_short(pl, seconds)) { -++ bd_free_mpls(pl); -++ return NULL; -++ } -++ } -++ if (repeats) { -++ if (!_filter_repeats(pl, repeats)) { -++ bd_free_mpls(pl); -++ return NULL; -++ } -++ } -++ if (dups) { -++ if (!_filter_dup(pl_list, pl_count, pl)) { -++ bd_free_mpls(pl); -++ return NULL; -++ } -++ } -++ if (verbose) { -++ indent_printf(0, -++ "%s -- Num Clips: %3d , Duration: minutes %4u:%02u", -++ basename(name), -++ pl->list_count, -++ _pl_duration(pl) / (45000 * 60), -++ (_pl_duration(pl) / 45000) % 60); -++ _show_ai(pl, 1); -++ } else { -++ indent_printf(0, "%s -- Duration: minutes %4u:%02u", -++ basename(name), -++ _pl_duration(pl) / (45000 * 60), -++ (_pl_duration(pl) / 45000) % 60); -++ } -++ if (playlist_info) { -++ _show_details(pl, 1); -++ } -++ if (chapter_marks) { -++ _show_marks(pl, 1); -++ } -++ if (pip_metadata) { -++ _show_pip_metadata(pl, 1); -++ } -++ if (clip_list) { -++ _show_clip_list(pl, 1); -++ } -++ if (sub_paths) { -++ _show_sub_paths(pl, 1); -++ _show_sub_paths_ss(pl, 1); -++ } -++ return pl; -++} -++ -++static void -++_usage(char *cmd) -++{ -++ fprintf(stderr, -++"Usage: %s -vli <mpls file> [<mpls file> ...]\n" -++"With no options, produces a list of the playlist(s) with durations\n" -++"Options:\n" -++" v - Verbose output.\n" -++" l - Produces a list of the m2ts clips\n" -++" i - Dumps detailed information about each clip\n" -++" c - Show chapter marks\n" -++" p - Show sub paths\n" -++" P - Show picture-in-picture metadata\n" -++" r <N> - Filter out titles that have >N repeating clips\n" -++" d - Filter out duplicate titles\n" -++" s <seconds> - Filter out short titles\n" -++" f - Filter combination -r2 -d -s900\n" -++, cmd); -++ -++ exit(EXIT_FAILURE); -++} -++ -++#define OPTS "vlicpPfr:ds:" -++ -++static int -++_qsort_str_cmp(const void *a, const void *b) -++{ -++ const char *stra = *(char * const *)a; -++ const char *strb = *(char * const *)b; -++ -++ return strcmp(stra, strb); -++} -++ -++int -++main(int argc, char *argv[]) -++{ -++ MPLS_PL *pl; -++ int opt; -++ int ii, pl_ii; -++ MPLS_PL *pl_list[1000]; -++ struct stat st; -++ char *path = NULL; -++ DIR *dir = NULL; -++ -++ do { -++ opt = getopt(argc, argv, OPTS); -++ switch (opt) { -++ case -1: -++ break; -++ -++ case 'v': -++ verbose = 1; -++ break; -++ -++ case 'l': -++ clip_list = 1; -++ break; -++ -++ case 'i': -++ playlist_info = 1; -++ break; -++ -++ case 'c': -++ chapter_marks = 1; -++ break; -++ -++ case 'p': -++ sub_paths = 1; -++ break; -++ -++ case 'P': -++ pip_metadata = 1; -++ break; -++ -++ case 'd': -++ dups = 1; -++ break; -++ -++ case 'r': -++ repeats = atoi(optarg); -++ break; -++ -++ case 'f': -++ repeats = 2; -++ dups = 1; -++ seconds = 900; -++ break; -++ -++ case 's': -++ seconds = atoi(optarg); -++ break; -++ -++ default: -++ _usage(argv[0]); -++ break; -++ } -++ } while (opt != -1); -++ -++ if (optind >= argc) { -++ _usage(argv[0]); -++ } -++ -++ for (pl_ii = 0, ii = optind; pl_ii < 1000 && ii < argc; ii++) { -++ -++ if (stat(argv[ii], &st)) { -++ continue; -++ } -++ dir = NULL; -++ if (S_ISDIR(st.st_mode)) { -++ -++ printf("Directory: %s:\n", argv[ii]); -++ path = _mk_path(argv[ii], PLAYLIST_DIR); -++ if (path == NULL) { -++ fprintf(stderr, "Failed to find playlist path: %s\n", argv[ii]); -++ continue; -++ } -++ dir = opendir(path); -++ if (dir == NULL) { -++ fprintf(stderr, "Failed to open dir: %s\n", path); -++ free(path); -++ continue; -++ } -++ } -++ if (dir != NULL) { -++ char **dirlist = (char**)calloc(10001, sizeof(char*)); -++ struct dirent *ent; -++ int jj = 0; -++ for (ent = readdir(dir); ent != NULL; ent = readdir(dir)) { -++ dirlist[jj++] = strcpy((char*)malloc(strlen(ent->d_name)), ent->d_name); -++ } -++ qsort(dirlist, jj, sizeof(char*), _qsort_str_cmp); -++ for (jj = 0; dirlist[jj] != NULL; jj++) { -++ char *name = NULL; -++ name = _mk_path(path, dirlist[jj]); -++ free(dirlist[jj]); -++ if (stat(name, &st)) { -++ free(name); -++ continue; -++ } -++ if (!S_ISREG(st.st_mode)) { -++ free(name); -++ continue; -++ } -++ pl = _process_file(name, pl_list, pl_ii); -++ free(name); -++ if (pl != NULL) { -++ pl_list[pl_ii++] = pl; -++ } -++ } -++ free(dirlist); -++ free(path); -++ closedir(dir); -++ dir = NULL; -++ } else { -++ pl = _process_file(argv[ii], pl_list, pl_ii); -++ if (pl != NULL) { -++ pl_list[pl_ii++] = pl; -++ } -++ } -++ } -++ // Cleanup -++ for (ii = 0; ii < pl_ii; ii++) { -++ bd_free_mpls(pl_list[ii]); -++ } -++ return 0; -++} -++ -+diff --git a/src/devtools/util.c b/src/devtools/util.c -+new file mode 100644 -+index 0000000..aaa4c46 -+--- /dev/null -++++ b/src/devtools/util.c -+@@ -0,0 +1,40 @@ -++/* -++ * This file is part of libbluray -++ * Copyright (C) 2009-2010 John Stebbins -++ * -++ * This library is free software; you can redistribute it and/or -++ * modify it under the terms of the GNU Lesser General Public -++ * License as published by the Free Software Foundation; either -++ * version 2.1 of the License, or (at your option) any later version. -++ * -++ * This library is distributed in the hope that it will be useful, -++ * but WITHOUT ANY WARRANTY; without even the implied warranty of -++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -++ * Lesser General Public License for more details. -++ * -++ * You should have received a copy of the GNU Lesser General Public -++ * License along with this library. If not, see -++ * <http://www.gnu.org/licenses/>. -++ */ -++ -++#include <stdio.h> -++#include <stdarg.h> -++ -++#include "util.h" -++ -++void -++indent_printf(int level, const char *fmt, ...) -++{ -++ va_list ap; -++ int ii; -++ -++ for (ii = 0; ii < level; ii++) -++ { -++ printf(" "); -++ } -++ va_start(ap, fmt); -++ vprintf(fmt, ap); -++ va_end(ap); -++ printf("\n"); -++} -++ -+diff --git a/src/devtools/util.h b/src/devtools/util.h -+new file mode 100644 -+index 0000000..144f8ec -+--- /dev/null -++++ b/src/devtools/util.h -+@@ -0,0 +1,43 @@ -++/* -++ * This file is part of libbluray -++ * Copyright (C) 2009-2010 John Stebbins -++ * -++ * This library is free software; you can redistribute it and/or -++ * modify it under the terms of the GNU Lesser General Public -++ * License as published by the Free Software Foundation; either -++ * version 2.1 of the License, or (at your option) any later version. -++ * -++ * This library is distributed in the hope that it will be useful, -++ * but WITHOUT ANY WARRANTY; without even the implied warranty of -++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -++ * Lesser General Public License for more details. -++ * -++ * You should have received a copy of the GNU Lesser General Public -++ * License along with this library. If not, see -++ * <http://www.gnu.org/licenses/>. -++ */ -++ -++#include <stdint.h> -++ -++#include "util/attributes.h" -++ -++#if defined( __MINGW32__ ) -++# undef lseek -++# define lseek _lseeki64 -++# undef fseeko -++# define fseeko fseeko64 -++# undef ftello -++# define ftello ftello64 -++# define flockfile(...) -++# define funlockfile(...) -++# define getc_unlocked getc -++# undef off_t -++# define off_t off64_t -++# undef stat -++# define stat _stati64 -++# define fstat _fstati64 -++# define wstat _wstati64 -++#endif -++ -++void indent_printf(int level, const char *fmt, ...) BD_ATTR_FORMAT_PRINTF(2,3); -++ -+diff --git a/src/examples/bdj_test.c b/src/examples/bdj_test.c -+deleted file mode 100644 -+index d9ebd16..0000000 -++++ /dev/null -+@@ -1,67 +0,0 @@ -+-/* -+- * This file is part of libbluray -+- * Copyright (C) 2010 William Hahne -+- * -+- * This program is free software; you can redistribute it and/or -+- * modify it under the terms of the GNU General Public License -+- * as published by the Free Software Foundation; either version 2 -+- * of the License, or (at your option) any later version. -+- * -+- * This program is distributed in the hope that it will be useful, -+- * but WITHOUT ANY WARRANTY; without even the implied warranty of -+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+- * GNU General Public License for more details. -+- * -+- * You should have received a copy of the GNU General Public License -+- * along with this program. If not, see <http://www.gnu.org/licenses/>. -+- * -+- * In addition, as a special exception, the copyright holders of libbluray -+- * gives permission to link the code of its release of libbluray with the -+- * OpenSSL project's "OpenSSL" library (or with modified versions of it -+- * that use the same license as the "OpenSSL" library), and distribute -+- * the linked executables. You must obey the GNU General Public License -+- * in all respects for all of the code used other than "OpenSSL". If you -+- * modify this file, you may extend this exception to your version of the -+- * file, but you are not obligated to do so. If you do not wish to do -+- * so, delete this exception statement from your version. -+- */ -+- -+-#include <stdio.h> -+-#include <stdlib.h> -+-#include <unistd.h> -+- -+-#include "libbluray/bluray.h" -+- -+-#if defined(_WIN32) -+-#include <windows.h> -+-#define sleep(x) Sleep(x) -+-#endif -+- -+-static void _usage(void) { -+- printf("Usage: [path to disc] [starting object]\n"); -+-} -+- -+-int main(int argc, char** argv) -+-{ -+- if (argc < 3) { -+- _usage(); -+- return 0; -+- } -+- -+- printf("%s %s\n", argv[1], argv[2]); -+- -+- BLURAY* bd = bd_open(argv[1], NULL); -+- -+- bd_get_titles(bd, TITLES_ALL, 0); -+- -+- if (!bd_start_bdj(bd, argv[2])) { -+- printf("Failed to start BD-J application.\n"); -+- } else { -+- while (1) { sleep(20); } -+- bd_stop_bdj(bd); -+- } -+- -+- bd_close(bd); -+- -+- return 0; -+-} -+diff --git a/src/examples/bdjo_dump.c b/src/examples/bdjo_dump.c -+deleted file mode 100644 -+index bcbd2af..0000000 -++++ /dev/null -+@@ -1,206 +0,0 @@ -+-/* -+- * This file is part of libbluray -+- * Copyright (C) 2014 Petri Hintukainen <phintuka@users.sourceforge.net> -+- * -+- * This library is free software; you can redistribute it and/or -+- * modify it under the terms of the GNU Lesser General Public -+- * License as published by the Free Software Foundation; either -+- * version 2.1 of the License, or (at your option) any later version. -+- * -+- * This library is distributed in the hope that it will be useful, -+- * but WITHOUT ANY WARRANTY; without even the implied warranty of -+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+- * Lesser General Public License for more details. -+- * -+- * You should have received a copy of the GNU Lesser General Public -+- * License along with this library. If not, see -+- * <http://www.gnu.org/licenses/>. -+- */ -+- -+-#include "libbluray/bluray.h" -+-#include "libbluray/bdj/bdjo_data.h" -+- -+-#include <stdio.h> -+-#include <string.h> -+- -+-static const char *_yes_no(int i) -+-{ -+- return i > 0 ? "yes" : i < 0 ? "unknown" : "no"; -+-} -+- -+-static const char *_binding_str(int i) -+-{ -+- switch (i) { -+- case 0: return "unbound"; -+- case 1: return "disc bound"; -+- case 3: return "title bound"; -+- default: return "???"; -+- } -+-} -+- -+-static const char *_visibility_str(int i) -+-{ -+- switch (i) { -+- case 0: return "none"; -+- case 1: return "applications"; -+- case 2: return "user"; -+- default: return "???"; -+- } -+-} -+- -+-static void _terminal_info_print(const BDJO_TERMINAL_INFO *p) -+-{ -+- printf("Terminal Info:\n"); -+- printf(" Default AWT font : %s\n", p->default_font); -+- printf(" initial HaVi config : %d\n", p->initial_havi_config_id); -+- printf(" Menu call mask : %d\n", p->menu_call_mask); -+- printf(" Title search mask : %d\n", p->menu_call_mask); -+-} -+- -+-static void _app_cache_item_print(const BDJO_APP_CACHE_ITEM *p) -+-{ -+- printf(" %3.3s: %s%s\n", -+- p->lang_code, p->ref_to_name, -+- p->type == 1 ? ".jar" : p->type == 2 ? "/" : " (unknown type)"); -+-} -+- -+-static void _app_cache_info_print(const BDJO_APP_CACHE_INFO *p) -+-{ -+- unsigned ii; -+- -+- printf("Application cache info:\n"); -+- for (ii = 0; ii < p->num_item; ii++) { -+- _app_cache_item_print(&p->item[ii]); -+- } -+-} -+- -+-static void _accessible_playlists_print(const BDJO_ACCESSIBLE_PLAYLISTS *p) -+-{ -+- unsigned ii; -+- -+- printf("Accessible playlists:\n"); -+- printf(" Access to all : %s\n", _yes_no(p->access_to_all_flag)); -+- printf(" Autostart first : %s\n", _yes_no(p->autostart_first_playlist_flag)); -+- -+- if (p->num_pl) { -+- printf(" Playlists : %d\n", p->num_pl); -+- for (ii = 0; ii < p->num_pl; ii++) { -+- printf(" %s.mpls\n", p->pl[ii].name); -+- } -+- } -+-} -+- -+-static void _app_profile_print(BDJO_APP_PROFILE *p) -+-{ -+- printf(" Profile %d Version %d.%d.%d\n", -+- p->profile_number, p->major_version, p->minor_version, p->micro_version); -+-} -+- -+-static void _app_print(const BDJO_APP *p) -+-{ -+- unsigned ii; -+- -+- printf(" Control code: : %d (%s)\n", p->control_code, -+- p->control_code == 1 ? "autostart" : p->control_code == 2 ? "present" : "???"); -+- printf(" Type : %d (%s)\n", p->type, -+- p->type == 1 ? "BD-J App" : "???"); -+- printf(" Organization ID : %08X\n", p->org_id); -+- printf(" Application ID : %04X\n", p->app_id); -+- printf(" Priority : %d\n", p->priority); -+- printf(" Binding : %d (%s)\n", p->binding, _binding_str(p->binding)); -+- printf(" Visibility : %d (%s)\n", p->visibility, _visibility_str(p->visibility)); -+- -+- if (p->num_profile) { -+- printf(" Profiles:\n"); -+- for (ii = 0; ii < p->num_profile; ii++) { -+- _app_profile_print(&p->profile[ii]); -+- } -+- } -+- -+- if (p->num_name) { -+- printf(" Names:\n"); -+- for (ii = 0; ii < p->num_name; ii++) { -+- printf(" %s: %s\n", p->name[ii].lang, p->name[ii].name); -+- } -+- } -+- -+- printf(" Base directory : %s\n", p->base_dir); -+- printf(" Icon locator : %s\n", p->icon_locator); -+- printf(" Icon flags : 0x%04x\n", p->icon_flags); -+- printf(" Classpath extension : %s\n", p->classpath_extension); -+- printf(" Initial class : %s\n", p->initial_class); -+- printf(" Parameters : "); -+- for (ii = 0; ii < p->num_param; ii++) { -+- printf("%s ", p->param[ii].param); -+- } -+- printf("\n"); -+-} -+- -+-static void _app_management_table_print(const BDJO_APP_MANAGEMENT_TABLE *p) -+-{ -+- unsigned ii; -+- -+- for (ii = 0; ii < p->num_app; ii++) { -+- printf("Application %d:\n", ii); -+- _app_print(&p->app[ii]); -+- } -+-} -+- -+-static void _key_interest_table_print(const BDJO_KEY_INTEREST_TABLE *p) -+-{ -+- unsigned int v; -+- memcpy(&v, p, sizeof(unsigned int)); -+- if (v) { -+- printf("Key interest table:\n"); -+- printf(" %s%s%s%s%s%s%s%s%s%s%s\n", -+- p->vk_play ? "VK_PLAY " : "", -+- p->vk_stop ? "VK_STOP " : "", -+- p->vk_ffw ? "VK_FFW " : "", -+- p->vk_rew ? "VK_REW " : "", -+- p->vk_track_next ? "VK_TRACK_NEXT " : "", -+- p->vk_track_prev ? "VK_TRACK_PREV " : "", -+- p->vk_pause ? "VK_PAUSE " : "", -+- p->vk_still_off ? "VK_STILL_OFF " : "", -+- p->vk_sec_audio_ena_dis ? "VK_SEC_AUDIO " : "", -+- p->vk_sec_video_ena_dis ? "VK_SEC_VIDEO " : "", -+- p->pg_textst_ena_dis ? "VK_PG_TEXTST " : ""); -+- } -+-} -+- -+-static void _file_access_info_print(const BDJO_FILE_ACCESS_INFO *p) -+-{ -+- printf("File access info:\n %s\n", p->path); -+-} -+- -+-static void _bdjo_print(const BDJO *p) -+-{ -+- _terminal_info_print(&p->terminal_info); -+- _app_cache_info_print(&p->app_cache_info); -+- _accessible_playlists_print(&p->accessible_playlists); -+- _app_management_table_print(&p->app_table); -+- _key_interest_table_print(&p->key_interest_table); -+- _file_access_info_print(&p->file_access_info); -+-} -+- -+-int main(int argc, const char *argv[]) -+-{ -+- if (argc < 2) { -+- fprintf(stderr, "usage: %s <bdjo_file>\n", argv[0]); -+- return 1; -+- } -+- -+- int cnt; -+- for (cnt = 1; cnt < argc; cnt++) { -+- -+- printf("%s\n", argv[cnt]); -+- -+- BDJO *bdjo = bd_read_bdjo(argv[cnt]); -+- if (bdjo) { -+- _bdjo_print(bdjo); -+- bd_free_bdjo(bdjo); -+- } -+- printf("\n"); -+- } -+- -+- return 0; -+-} -+diff --git a/src/examples/clpi_dump.c b/src/examples/clpi_dump.c -+deleted file mode 100644 -+index bd64783..0000000 -++++ /dev/null -+@@ -1,487 +0,0 @@ -+-/* -+- * This file is part of libbluray -+- * Copyright (C) 2009-2010 John Stebbins -+- * Copyright (C) 2012-2013 Petri Hintukainen <phintuka@users.sourceforge.net> -+- * -+- * This library is free software; you can redistribute it and/or -+- * modify it under the terms of the GNU Lesser General Public -+- * License as published by the Free Software Foundation; either -+- * version 2.1 of the License, or (at your option) any later version. -+- * -+- * This library is distributed in the hope that it will be useful, -+- * but WITHOUT ANY WARRANTY; without even the implied warranty of -+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+- * Lesser General Public License for more details. -+- * -+- * You should have received a copy of the GNU Lesser General Public -+- * License along with this library. If not, see -+- * <http://www.gnu.org/licenses/>. -+- */ -+- -+-#include <stdio.h> -+-#include <stdlib.h> -+-#include <unistd.h> -+-#include <inttypes.h> -+- -+-#include "libbluray/bdnav/clpi_data.h" -+-#include "libbluray/bluray.h" -+- -+-#include "util.h" -+- -+-static int verbose; -+- -+-typedef struct { -+- int value; -+- const char *str; -+-} VALUE_MAP; -+- -+-static inline const char* -+-_lookup_str(const VALUE_MAP *map, int val) -+-{ -+- int ii; -+- -+- for (ii = 0; map[ii].str; ii++) { -+- if (val == map[ii].value) { -+- return map[ii].str; -+- } -+- } -+- return "?"; -+-} -+- -+-const VALUE_MAP codec_map[] = { -+- {0x01, "MPEG-1 Video"}, -+- {0x02, "MPEG-2 Video"}, -+- {0x03, "MPEG-1 Audio"}, -+- {0x04, "MPEG-2 Audio"}, -+- {0x80, "LPCM"}, -+- {0x81, "AC-3"}, -+- {0x82, "DTS"}, -+- {0x83, "TrueHD"}, -+- {0x84, "AC-3 Plus"}, -+- {0x85, "DTS-HD"}, -+- {0x86, "DTS-HD Master"}, -+- {0xa1, "AC-3 Plus for secondary audio"}, -+- {0xa2, "DTS-HD for secondary audio"}, -+- {0xea, "VC-1"}, -+- {0x1b, "H.264"}, -+- {0x20, "H.264 MVC dep."}, -+- {0x90, "Presentation Graphics"}, -+- {0x91, "Presentation Graphics"}, -+- {0x92, "Interactive Graphics"}, -+- {0, NULL} -+-}; -+- -+-const VALUE_MAP video_format_map[] = { -+- {0, "Reserved"}, -+- {1, "480i"}, -+- {2, "576i"}, -+- {3, "480p"}, -+- {4, "1080i"}, -+- {5, "720p"}, -+- {6, "1080p"}, -+- {7, "576p"}, -+- {0, NULL} -+-}; -+- -+-const VALUE_MAP video_rate_map[] = { -+- {0, "Reserved1"}, -+- {1, "23.976"}, -+- {2, "24"}, -+- {3, "25"}, -+- {4, "29.97"}, -+- {5, "Reserved2"}, -+- {6, "50"}, -+- {7, "59.94"}, -+- {0, NULL} -+-}; -+- -+-const VALUE_MAP video_aspect_map[] = { -+- {0, "Reserved1"}, -+- {1, "Reserved2"}, -+- {2, "4:3"}, -+- {3, "16:9"}, -+- {0, NULL} -+-}; -+- -+-const VALUE_MAP audio_format_map[] = { -+- {0, "Reserved1"}, -+- {1, "Mono"}, -+- {2, "Reserved2"}, -+- {3, "Stereo"}, -+- {4, "Reserved3"}, -+- {5, "Reserved4"}, -+- {6, "Multi Channel"}, -+- {12, "Combo"}, -+- {0, NULL} -+-}; -+- -+-const VALUE_MAP audio_rate_map[] = { -+- {0, "Reserved1"}, -+- {1, "48 Khz"}, -+- {2, "Reserved2"}, -+- {3, "Reserved3"}, -+- {4, "96 Khz"}, -+- {5, "192 Khz"}, -+- {12, "48/192 Khz"}, -+- {14, "48/96 Khz"}, -+- {0, NULL} -+-}; -+- -+-const VALUE_MAP application_type_map[] = { -+- {1, "Main TS for a main-path of Movie"}, -+- {2, "Main TS for a main-path of Time based slide show"}, -+- {3, "Main TS for a main-path of Browsable slide show"}, -+- {4, "Sub TS for a sub-path of Browsable slide show"}, -+- {5, "Sub TS for a sub-path of Interactive Graphics menu"}, -+- {6, "Sub TS for a sub-path of Text subtitle"}, -+- {7, "Sub TS for a sub-path of one or more elementary streams path"}, -+- {0, NULL}, -+-}; -+- -+-static void -+-_show_stream(CLPI_PROG_STREAM *ss, int level) -+-{ -+- indent_printf(level, "Codec (%04x): %s", ss->coding_type, -+- _lookup_str(codec_map, ss->coding_type)); -+- indent_printf(level, "PID: %04x", ss->pid); -+- switch (ss->coding_type) { -+- case 0x01: -+- case 0x02: -+- case 0xea: -+- case 0x1b: -+- case 0x20: -+- indent_printf(level, "Format %02x: %s", ss->format, -+- _lookup_str(video_format_map, ss->format)); -+- indent_printf(level, "Rate %02x: %s", ss->rate, -+- _lookup_str(video_rate_map, ss->rate)); -+- indent_printf(level, "Aspect %02x: %s", ss->aspect, -+- _lookup_str(video_aspect_map, ss->aspect)); -+- indent_printf(level, "oc_flag %02x", ss->oc_flag); -+- break; -+- -+- case 0x03: -+- case 0x04: -+- case 0x80: -+- case 0x81: -+- case 0x82: -+- case 0x83: -+- case 0x84: -+- case 0x85: -+- case 0x86: -+- case 0xa1: -+- case 0xa2: -+- indent_printf(level, "Format %02x: %s", ss->format, -+- _lookup_str(audio_format_map, ss->format)); -+- indent_printf(level, "Rate %02x: %s", ss->rate, -+- _lookup_str(audio_rate_map, ss->rate)); -+- indent_printf(level, "Language: %s", ss->lang); -+- break; -+- -+- case 0x90: -+- case 0x91: -+- case 0xa0: -+- indent_printf(level, "Language: %s", ss->lang); -+- break; -+- -+- case 0x92: -+- indent_printf(level, "Char Code: %02x", ss->char_code); -+- indent_printf(level, "Language: %s", ss->lang); -+- break; -+- -+- default: -+- fprintf(stderr, "unrecognized coding type %02x\n", ss->coding_type); -+- break; -+- }; -+-} -+- -+-static void -+-_show_clip_info(CLPI_CL *cl, int level) -+-{ -+- CLPI_CLIP_INFO *ci = &cl->clip; -+- int ii; -+- -+- indent_printf(level, "Clip Info"); -+- indent_printf(level+1, "Clip Stream Type: %02x", ci->clip_stream_type); -+- indent_printf(level+1, "Clip Application Type (%02x): %s", -+- ci->application_type, _lookup_str(application_type_map, ci->application_type)); -+- indent_printf(level+1, "is_ATC_delta: %s", ci->is_atc_delta ? "True" : "False"); -+- indent_printf(level+1, "ATC delta count: %d", ci->atc_delta_count); -+- indent_printf(level+1, "TS Recording Rate: %u", ci->ts_recording_rate); -+- indent_printf(level+1, "Number Source Packets: %u", ci->num_source_packets); -+- // Show ts type info -+- indent_printf(level+1, "TS Type Info"); -+- indent_printf(level+2, "Validity Flags %02x", ci->ts_type_info.validity); -+- indent_printf(level+2, "Format Id %s", ci->ts_type_info.format_id); -+- // Show cc5 thing -+- for (ii = 0; ii < ci->atc_delta_count; ii++) { -+- indent_printf(level+1, "ATC delta[ %d ]", ii); -+- indent_printf(level+2, "Delta %08x", ci->atc_delta[ii].delta); -+- indent_printf(level+2, "File Id %s", ci->atc_delta[ii].file_id); -+- indent_printf(level+2, "File Code %s", ci->atc_delta[ii].file_code); -+- } -+- // show fonts -+- if (cl->font_info.font_count) { -+- indent_printf(level+1, "Font files"); -+- for (ii = 0; ii < cl->font_info.font_count; ii++) { -+- indent_printf(level+2, "Font file %d: %s.otf", ii+1, cl->font_info.font[ii].file_id); -+- } -+- } -+- -+- printf("\n"); -+-} -+- -+-static void -+-_show_seq_info(CLPI_SEQ_INFO *si, int level) -+-{ -+- CLPI_ATC_SEQ *atc; -+- CLPI_STC_SEQ *stc; -+- int ii, jj; -+- -+- indent_printf(level, "Sequence Info"); -+- indent_printf(level+1, "Number ATC Sequences: %d", si->num_atc_seq); -+- for (ii = 0; ii < si->num_atc_seq; ii++) { -+- atc = &si->atc_seq[ii]; -+- indent_printf(level+1, "ATC Sequence %d", ii); -+- indent_printf(level+2, "SPN ATC Start: %u", atc->spn_atc_start); -+- indent_printf(level+2, "Offset STC Id: %d", atc->offset_stc_id); -+- indent_printf(level+2, "Number STC Sequences: %d", atc->num_stc_seq); -+- for (jj = 0; jj < atc->num_stc_seq; jj++) { -+- stc = &atc->stc_seq[jj]; -+- indent_printf(level+2, "ATC Sequence %d", jj); -+- indent_printf(level+3, "SPN STC Start: %u", stc->spn_stc_start); -+- indent_printf(level+3, "PCR PID: %04x", stc->pcr_pid); -+- indent_printf(level+3, "Presentation Start: %u", -+- stc->presentation_start_time); -+- indent_printf(level+3, "Presentation End: %u", -+- stc->presentation_end_time); -+- } -+- } -+-} -+- -+-static void -+-_show_prog_info(CLPI_PROG_INFO *pi, int level) -+-{ -+- CLPI_PROG *prog; -+- int ii, jj; -+- -+- indent_printf(level, "Program Info"); -+- indent_printf(level+1, "Number Programs: %d", pi->num_prog); -+- for (ii = 0; ii < pi->num_prog; ii++) { -+- prog = &pi->progs[ii]; -+- indent_printf(level+1, "Program %d", ii); -+- indent_printf(level+2, "SPN Program Sequence Start: %d", -+- prog->spn_program_sequence_start); -+- indent_printf(level+2, "Program Map PID: %d", prog->program_map_pid); -+- indent_printf(level+2, "Number Streams: %d", prog->num_streams); -+- indent_printf(level+2, "Number Groups: %d", prog->num_groups); -+- for (jj = 0; jj < prog->num_streams; jj++) { -+- indent_printf(level+2, "Stream %d", jj); -+- _show_stream(&prog->streams[jj], level+3); -+- } -+- } -+-} -+- -+-static void -+-_show_extent_start(CLPI_EXTENT_START *es, int level) -+-{ -+- unsigned int ii; -+- -+- indent_printf(level, "Extension data: Extent Start Point"); -+- -+- if (!es->num_point) { -+- indent_printf(level+1, "(no data)"); -+- -+- } else { -+- indent_printf(level+1, "Number of Start Points: %d", es->num_point); -+- -+- if (verbose) { -+- for (ii = 0; ii < es->num_point; ii++) { -+- indent_printf(level+1, "Extent %5d: SPN 0x%08X", ii, es->point[ii]); -+- } -+- } -+- } -+-} -+- -+-static void -+-_show_cpi_info(CLPI_CPI *cpi, int level) -+-{ -+- CLPI_EP_MAP_ENTRY *entry; -+- CLPI_EP_COARSE *coarse; -+- CLPI_EP_FINE *fine; -+- int ii, jj, kk; -+- -+- indent_printf(level, "CPI"); -+- indent_printf(level+1, "Number Stream PID: %d", cpi->num_stream_pid); -+- for (ii = 0; ii < cpi->num_stream_pid; ii++) { -+- entry = &cpi->entry[ii]; -+- indent_printf(level+1, "Stream: %d", ii); -+- indent_printf(level+2, "PID: %04x", entry->pid); -+- indent_printf(level+2, "EP Stream Type: %d", entry->ep_stream_type); -+- indent_printf(level+2, "Number EP Coarse: %d", entry->num_ep_coarse); -+- indent_printf(level+2, "Number EP Fine: %d", entry->num_ep_fine); -+- indent_printf(level+2, "EP Map Start: %d", -+- entry->ep_map_stream_start_addr); -+- for (jj = 0; jj < entry->num_ep_coarse; jj++) { -+- coarse = &entry->coarse[jj]; -+- indent_printf(level+2, "Coarse: %d", jj); -+- indent_printf(level+3, "Ref EP Fine: %d", coarse->ref_ep_fine_id); -+- indent_printf(level+3, "PTS EP: %d", coarse->pts_ep); -+- indent_printf(level+3, "SPN EP: %d", coarse->spn_ep); -+- } -+- for (jj = 0; jj < entry->num_ep_fine; jj++) { -+- fine = &entry->fine[jj]; -+- indent_printf(level+2, "Fine: %d", jj); -+- indent_printf(level+3, "Angle Change Point: %s", -+- fine->is_angle_change_point ? "True":"False"); -+- indent_printf(level+3, "I End Offset: %d", -+- fine->i_end_position_offset); -+- indent_printf(level+3, "PTS EP: %d", fine->pts_ep); -+- indent_printf(level+3, "SPN EP: %d", fine->spn_ep); -+- } -+- if (verbose) { -+- uint64_t pts; -+- uint32_t spn; -+- -+- indent_printf(level+2, "PTS - SPN Map"); -+- for (jj = 0; jj < entry->num_ep_coarse; jj++) { -+- int start, end; -+- -+- indent_printf(level+3, "Coarse: %d", jj); -+- coarse = &entry->coarse[jj]; -+- start = coarse->ref_ep_fine_id; -+- if (jj < entry->num_ep_coarse - 1) { -+- end = entry->coarse[jj+1].ref_ep_fine_id; -+- } else { -+- end = entry->num_ep_fine; -+- } -+- for (kk = start; kk < end; kk++) { -+- fine = &entry->fine[kk]; -+- pts = ((uint64_t) (coarse->pts_ep & ~0x01) << 19) + -+- ((uint64_t)fine->pts_ep << 9); -+- spn = (coarse->spn_ep & ~0x1FFFF) + fine->spn_ep; -+- indent_printf(level+4, "PTS %8"PRIu64"/%8"PRIu64" -- SPN %u", -+- pts, pts >> 1, spn); -+- } -+- } -+- } -+- } -+-} -+- -+- -+-static void -+-_usage(char *cmd) -+-{ -+- fprintf(stderr, -+-"Usage: %s -vcspi <clpi file> [<clpi file> ...]\n" -+-"With no options, produces no output (not very useful)\n" -+-"Options:\n" -+-" v - Verbose output.\n" -+-" c - Shows the Clip Info structure\n" -+-" s - Shows the Sequence Info structure\n" -+-" p - Shows the Program Info structure\n" -+-" i - Shows the CPI. PTS to SPN map\n" -+-" e - Shows Extent Start Table\n" -+-, cmd); -+- -+- exit(EXIT_FAILURE); -+-} -+- -+-#define OPTS "vcspie" -+- -+-int -+-main(int argc, char *argv[]) -+-{ -+- CLPI_CL *cl; -+- int opt; -+- int opt_clip_info = 0, opt_seq_info = 0, opt_prog_info = 0; -+- int opt_cpi_info = 0, opt_extent_start = 0; -+- int ii; -+- -+- do { -+- opt = getopt(argc, argv, OPTS); -+- switch (opt) { -+- case -1: break; -+- -+- case 'v': -+- verbose = 1; -+- break; -+- -+- case 's': -+- opt_seq_info = 1; -+- break; -+- -+- case 'i': -+- opt_cpi_info = 1; -+- break; -+- -+- case 'c': -+- opt_clip_info = 1; -+- break; -+- -+- case 'p': -+- opt_prog_info = 1; -+- break; -+- -+- case 'e': -+- opt_extent_start = 1; -+- break; -+- -+- default: -+- _usage(argv[0]); -+- break; -+- } -+- } while (opt != -1); -+- -+- if (optind >= argc) { -+- _usage(argv[0]); -+- } -+- -+- for (ii = optind; ii < argc; ii++) { -+- cl = bd_read_clpi(argv[ii]); -+- if (cl == NULL) { -+- fprintf(stderr, "Parsing %s failed\n", argv[ii]); -+- continue; -+- } -+- if (opt_clip_info) { -+- // Show clip info -+- _show_clip_info(cl, 1); -+- } -+- if (opt_seq_info) { -+- // Show sequence info -+- _show_seq_info(&cl->sequence, 1); -+- } -+- if (opt_prog_info) { -+- // Show program info -+- _show_prog_info(&cl->program, 1); -+- } -+- if (opt_cpi_info) { -+- // Show cpi -+- _show_cpi_info(&cl->cpi, 1); -+- } -+- -+- if (opt_prog_info) { -+- if (cl->program_ss.num_prog) { -+- printf("\n"); -+- indent_printf(1, "Extension: Program Info SS"); -+- _show_prog_info(&cl->program_ss, 1); -+- } -+- } -+- if (opt_cpi_info) { -+- if (cl->program_ss.num_prog) { -+- printf("\n"); -+- indent_printf(1, "Extension: CPI SS"); -+- _show_cpi_info(&cl->cpi_ss, 1); -+- } -+- } -+- if (opt_extent_start) { -+- // Show extent start point -+- if (cl->extent_start.num_point > 0) { -+- _show_extent_start(&cl->extent_start, 1); -+- } -+- } -+- -+- bd_free_clpi(cl); -+- } -+- return 0; -+-} -+- -+diff --git a/src/examples/hdmv_test.c b/src/examples/hdmv_test.c -+deleted file mode 100644 -+index 585ed70..0000000 -++++ /dev/null -+@@ -1,257 +0,0 @@ -+-/* -+- * This file is part of libbluray -+- * Copyright (C) 2010 hpi1 -+- * -+- * This library is free software; you can redistribute it and/or -+- * modify it under the terms of the GNU Lesser General Public -+- * License as published by the Free Software Foundation; either -+- * version 2.1 of the License, or (at your option) any later version. -+- * -+- * This library is distributed in the hope that it will be useful, -+- * but WITHOUT ANY WARRANTY; without even the implied warranty of -+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+- * Lesser General Public License for more details. -+- * -+- * You should have received a copy of the GNU Lesser General Public -+- * License along with this library. If not, see -+- * <http://www.gnu.org/licenses/>. -+- */ -+- -+-#include <stdio.h> -+-#include <stdlib.h> -+-#include <string.h> -+-#include <inttypes.h> -+- -+-#include "util/log_control.h" -+-#include "libbluray/bluray.h" -+- -+-static void _print_event(BD_EVENT *ev) -+-{ -+- switch (ev->event) { -+- case BD_EVENT_NONE: -+- break; -+- case BD_EVENT_ERROR: -+- printf("EVENT_ERROR:\t%d\n", ev->param); -+- break; -+- case BD_EVENT_READ_ERROR: -+- printf("EVENT_READ_ERROR:\t%d\n", ev->param); -+- break; -+- case BD_EVENT_ENCRYPTED: -+- printf("EVENT_ENCRYPTED:\t%d\n", ev->param); -+- break; -+- -+- /* current playback position */ -+- -+- case BD_EVENT_ANGLE: -+- printf("EVENT_ANGLE:\t%d\n", ev->param); -+- break; -+- case BD_EVENT_TITLE: -+- printf("EVENT_TITLE:\t%d\n", ev->param); -+- break; -+- case BD_EVENT_PLAYLIST: -+- printf("EVENT_PLAYLIST:\t%d\n", ev->param); -+- break; -+- case BD_EVENT_PLAYITEM: -+- printf("EVENT_PLAYITEM:\t%d\n", ev->param); -+- break; -+- case BD_EVENT_CHAPTER: -+- printf("EVENT_CHAPTER:\t%d\n", ev->param); -+- break; -+- -+- /* */ -+- -+- case BD_EVENT_STILL: -+- printf("EVENT_STILL:\t%d\n", ev->param); -+- break; -+- -+- case BD_EVENT_SEEK: -+- printf("EVENT_SEEK:\t%d\n", ev->param); -+- break; -+- -+- case BD_EVENT_STILL_TIME: -+- if (ev->param) { -+- printf("EVENT_STILL_TIME:\t%d\n", ev->param); -+- } else { -+- printf("EVENT_STILL_TIME:\tinfinite\n"); -+- } -+- break; -+- -+- /* stream selection */ -+- -+- case BD_EVENT_AUDIO_STREAM: -+- printf("EVENT_AUDIO_STREAM:\t%d\n", ev->param); -+- break; -+- case BD_EVENT_IG_STREAM: -+- printf("EVENT_IG_STREAM:\t%d\n", ev->param); -+- break; -+- case BD_EVENT_PG_TEXTST_STREAM: -+- printf("EVENT_PG_TEXTST_STREAM:\t%d\n", ev->param); -+- break; -+- case BD_EVENT_SECONDARY_AUDIO_STREAM: -+- printf("EVENT_SECONDARY_AUDIO_STREAM:\t%d\n", ev->param); -+- break; -+- case BD_EVENT_SECONDARY_VIDEO_STREAM: -+- printf("EVENT_SECONDARY_VIDEO_STREAM:\t%d\n", ev->param); -+- break; -+- -+- case BD_EVENT_PG_TEXTST: -+- printf("EVENT_PG_TEXTST:\t%s\n", ev->param ? "enable" : "disable"); -+- break; -+- case BD_EVENT_SECONDARY_AUDIO: -+- printf("EVENT_SECONDARY_AUDIO:\t%s\n", ev->param ? "enable" : "disable"); -+- break; -+- case BD_EVENT_SECONDARY_VIDEO: -+- printf("EVENT_SECONDARY_VIDEO:\t%s\n", ev->param ? "enable" : "disable"); -+- break; -+- case BD_EVENT_SECONDARY_VIDEO_SIZE: -+- printf("EVENT_SECONDARY_VIDEO_SIZE:\t%s\n", ev->param==0 ? "PIP" : "fullscreen"); -+- break; -+- -+- default: -+- printf("UNKNOWN EVENT %d:\t%d\n", ev->event, ev->param); -+- break; -+- } -+- -+- fflush(stdout); -+-} -+- -+-static void _read_to_eof(BLURAY *bd) -+-{ -+- BD_EVENT ev; -+- int bytes; -+- uint64_t total = 0; -+- uint8_t buf[6144]; -+- -+- bd_seek(bd, bd_get_title_size(bd) - 6144); -+- -+- do { -+- bytes = bd_read_ext(bd, buf, 6144, &ev); -+- total += bytes < 0 ? 0 : bytes; -+- _print_event(&ev); -+- } while (bytes > 0); -+- -+- printf("_read_to_eof(): read %"PRIu64" bytes\n", total); -+-} -+- -+-static void _print_events(BLURAY *bd) -+-{ -+- BD_EVENT ev; -+- -+- do { -+- bd_read_ext(bd, NULL, 0, &ev); -+- _print_event(&ev); -+- } while (ev.event != BD_EVENT_NONE && ev.event != BD_EVENT_ERROR); -+-} -+- -+-static void _play_pl(BLURAY *bd) -+-{ -+- printf("Playing playlist\n"); -+- -+- fflush(stdout); -+- _read_to_eof(bd); -+- -+- printf("Playing playlist done\n\n"); -+- -+- _print_events(bd); -+- -+- printf("\n"); -+-} -+- -+-int main(int argc, char *argv[]) -+-{ -+- int title = -1; -+- int verbose = 0; -+- int args = 0; -+- -+- /* -+- * parse arguments -+- */ -+- -+- if (argc < 2) { -+- printf("\nUsage:\n %s [-v] [-t <title>] <media_path> [<keyfile_path>]\n\n", argv[0]); -+- return -1; -+- } -+- -+- if (!strcmp(argv[1+args], "-v")) { -+- verbose = 1; -+- args++; -+- } -+- -+- if (!strcmp(argv[1+args], "-t")) { -+- args++; -+- title = atoi(argv[1+args]); -+- args++; -+- printf("Requested title %d\n", title); -+- } -+- -+- if (verbose) { -+- printf("Enabling verbose debug\n"); -+- bd_set_debug_mask(bd_get_debug_mask() | DBG_HDMV | DBG_BLURAY); -+- } -+- -+- printf("\n"); -+- -+- /* -+- * open and setup -+- */ -+- -+- BLURAY *bd = bd_open(argv[1+args], argv[2+args]); -+- -+- if (!bd) { -+- printf("bd_open(\'%s\') failed\n", argv[1]); -+- return -1; -+- } -+- -+- bd_set_player_setting (bd, BLURAY_PLAYER_SETTING_PARENTAL, 99); -+- bd_set_player_setting_str(bd, BLURAY_PLAYER_SETTING_AUDIO_LANG, "eng"); -+- bd_set_player_setting_str(bd, BLURAY_PLAYER_SETTING_PG_LANG, "eng"); -+- bd_set_player_setting_str(bd, BLURAY_PLAYER_SETTING_MENU_LANG, "eng"); -+- bd_set_player_setting_str(bd, BLURAY_PLAYER_SETTING_COUNTRY_CODE, NULL); -+- -+- /* -+- * play -+- */ -+- -+- printf("Running first play movie object\n"); -+- -+- fflush(stdout); -+- bd_play(bd); -+- -+- _print_events(bd); -+- -+- printf("\n"); -+- -+- /* -+- * play title -+- */ -+- -+- if (title >= 0) { -+- printf("Playing title %d\n", title); -+- -+- fflush(stdout); -+- bd_play_title(bd, title); -+- -+- _print_events(bd); -+- -+- printf("\n"); -+- } -+- -+- /* -+- * play playlist -+- */ -+- -+- _play_pl(bd); -+- -+- _play_pl(bd); -+- -+- _play_pl(bd); -+- -+- /* -+- * clean up -+- */ -+- -+- bd_close(bd); -+- -+- return 0; -+-} -+- -+diff --git a/src/examples/list_titles.c b/src/examples/list_titles.c -+index 2e0cae8..768f078 100644 -+--- a/src/examples/list_titles.c -++++ b/src/examples/list_titles.c -+@@ -78,7 +78,10 @@ int main(int argc, char *argv[]) -+ _usage(argv[0]); -+ } -+ bd = bd_open(bd_dir, NULL); -+- -++ if (!bd) { -++ fprintf(stderr, "bd_open(%s) failed\n", bd_dir); -++ exit(EXIT_FAILURE); -++ } -+ count = bd_get_titles(bd, flags, seconds); -+ main_title = bd_get_main_title(bd); -+ if (main_title >= 0) { -+@@ -89,7 +92,7 @@ int main(int argc, char *argv[]) -+ BLURAY_TITLE_INFO* ti; -+ ti = bd_get_title_info(bd, ii, 0); -+ printf( -+- "index: %d duration: %02"PRIu64":%02"PRIu64":%02"PRIu64" chapters: %3d angles: %2u clips: %3u (playlist: %05d.mpls) " -++ "index: %3d duration: %02"PRIu64":%02"PRIu64":%02"PRIu64" chapters: %3d angles: %2u clips: %3u (playlist: %05d.mpls) " -+ "V:%d A:%-2d PG:%-2d IG:%-2d SV:%d SA:%d\n", -+ ii + 1, -+ (ti->duration / 90000) / (3600), -+diff --git a/src/examples/mobj_dump.c b/src/examples/mobj_dump.c -+deleted file mode 100644 -+index 3eaf9f4..0000000 -++++ /dev/null -+@@ -1,83 +0,0 @@ -+-/* -+- * This file is part of libbluray -+- * Copyright (C) 2010 hpi1 -+- * -+- * This library is free software; you can redistribute it and/or -+- * modify it under the terms of the GNU Lesser General Public -+- * License as published by the Free Software Foundation; either -+- * version 2.1 of the License, or (at your option) any later version. -+- * -+- * This library is distributed in the hope that it will be useful, -+- * but WITHOUT ANY WARRANTY; without even the implied warranty of -+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+- * Lesser General Public License for more details. -+- * -+- * You should have received a copy of the GNU Lesser General Public -+- * License along with this library. If not, see -+- * <http://www.gnu.org/licenses/>. -+- */ -+- -+-#include "libbluray/bluray.h" -+- -+-#include "libbluray/hdmv/mobj_data.h" -+-#include "libbluray/hdmv/mobj_print.h" -+- -+-#include <stdio.h> -+-#include <string.h> -+- -+-static void _mobj_print(MOBJ_OBJECTS *objects, int disasm) -+-{ -+- int o, c; -+- -+- printf("Number of objects: %d\n", objects->num_objects); -+- -+- for (o = 0; o < objects->num_objects; o++) { -+- -+- printf("Object %d:\n" -+- " number of commands: %d\n" -+- " resume intention flag: %d\n" -+- " menu call mask: %d\n" -+- " title search mask: %d\n", -+- o, objects->objects[o].num_cmds, -+- objects->objects[o].resume_intention_flag, -+- objects->objects[o].menu_call_mask, -+- objects->objects[o].title_search_mask); -+- -+- if (disasm) { -+- printf(" program:\n"); -+- for (c = 0; c < objects->objects[o].num_cmds; c++) { -+- char buf[256]; -+- mobj_sprint_cmd(buf, &objects->objects[o].cmds[c]); -+- printf(" %04d: %s\n", c, buf); -+- } -+- } -+- } -+-} -+- -+-int main(int argc, const char *argv[]) -+-{ -+- int disasm = 0; -+- MOBJ_OBJECTS *mobj = NULL; -+- -+- if (argc < 2) { -+- fprintf(stderr, -+- "usage: %s [-d] <file>\n" -+- "Options:\n" -+- " d disassemble object code\n", -+- argv[0]); -+- return 1; -+- } -+- if (argc > 2) { -+- disasm = !strcmp(argv[1], "-d"); -+- } -+- -+- mobj = bd_read_mobj(argv[argc-1]); -+- -+- if (mobj) { -+- _mobj_print(mobj, disasm); -+- -+- bd_free_mobj(mobj); -+- } -+- -+- return 0; -+-} -+diff --git a/src/examples/mpls_dump.c b/src/examples/mpls_dump.c -+deleted file mode 100644 -+index 619b6b2..0000000 -++++ /dev/null -+@@ -1,797 +0,0 @@ -+-/* -+- * This file is part of libbluray -+- * Copyright (C) 2009-2010 John Stebbins -+- * -+- * This library is free software; you can redistribute it and/or -+- * modify it under the terms of the GNU Lesser General Public -+- * License as published by the Free Software Foundation; either -+- * version 2.1 of the License, or (at your option) any later version. -+- * -+- * This library is distributed in the hope that it will be useful, -+- * but WITHOUT ANY WARRANTY; without even the implied warranty of -+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+- * Lesser General Public License for more details. -+- * -+- * You should have received a copy of the GNU Lesser General Public -+- * License along with this library. If not, see -+- * <http://www.gnu.org/licenses/>. -+- */ -+- -+-#include <sys/stat.h> -+-#include <dirent.h> -+-#include <stdio.h> -+-#include <stdlib.h> -+-#include <unistd.h> -+-#include <string.h> -+-#include <libgen.h> -+- -+-#include "libbluray/bdnav/mpls_parse.h" -+-#include "libbluray/bluray.h" -+- -+-#include "util.h" -+- -+-#ifdef _WIN32 -+-# define DIR_SEP "\\" -+-# define PLAYLIST_DIR "\\BDMV\\PLAYLIST" -+-#else -+-# define DIR_SEP "/" -+-# define PLAYLIST_DIR "/BDMV/PLAYLIST" -+-#endif -+- -+- -+-static int verbose; -+- -+-typedef struct { -+- int value; -+- const char *str; -+-} VALUE_MAP; -+- -+-const VALUE_MAP codec_map[] = { -+- {0x01, "MPEG-1 Video"}, -+- {0x02, "MPEG-2 Video"}, -+- {0x03, "MPEG-1 Audio"}, -+- {0x04, "MPEG-2 Audio"}, -+- {0x80, "LPCM"}, -+- {0x81, "AC-3"}, -+- {0x82, "DTS"}, -+- {0x83, "TrueHD"}, -+- {0x84, "AC-3 Plus"}, -+- {0x85, "DTS-HD"}, -+- {0x86, "DTS-HD Master"}, -+- {0xa1, "AC-3 Plus for secondary audio"}, -+- {0xa2, "DTS-HD for secondary audio"}, -+- {0xea, "VC-1"}, -+- {0x1b, "H.264"}, -+- {0x90, "Presentation Graphics"}, -+- {0x91, "Interactive Graphics"}, -+- {0x92, "Text Subtitle"}, -+- {0, NULL} -+-}; -+- -+-const VALUE_MAP video_format_map[] = { -+- {0, "Reserved"}, -+- {1, "480i"}, -+- {2, "576i"}, -+- {3, "480p"}, -+- {4, "1080i"}, -+- {5, "720p"}, -+- {6, "1080p"}, -+- {7, "576p"}, -+- {0, NULL} -+-}; -+- -+-const VALUE_MAP video_rate_map[] = { -+- {0, "Reserved1"}, -+- {1, "23.976"}, -+- {2, "24"}, -+- {3, "25"}, -+- {4, "29.97"}, -+- {5, "Reserved2"}, -+- {6, "50"}, -+- {7, "59.94"}, -+- {0, NULL} -+-}; -+- -+-const VALUE_MAP audio_format_map[] = { -+- {0, "Reserved1"}, -+- {1, "Mono"}, -+- {2, "Reserved2"}, -+- {3, "Stereo"}, -+- {4, "Reserved3"}, -+- {5, "Reserved4"}, -+- {6, "Multi Channel"}, -+- {12, "Combo"}, -+- {0, NULL} -+-}; -+- -+-const VALUE_MAP audio_rate_map[] = { -+- {0, "Reserved1"}, -+- {1, "48 Khz"}, -+- {2, "Reserved2"}, -+- {3, "Reserved3"}, -+- {4, "96 Khz"}, -+- {5, "192 Khz"}, -+- {12, "48/192 Khz"}, -+- {14, "48/96 Khz"}, -+- {0, NULL} -+-}; -+- -+-const VALUE_MAP subpath_type_map[] = { -+- {2, "Primary audio of the Browsable slideshow"}, -+- {3, "Interactive Graphics presentation menu"}, -+- {4, "Text Subtitle"}, -+- {5, "Out-of-mux Synchronous elementary streams"}, -+- {6, "Out-of-mux Asynchronous Picture-in-Picture presentation"}, -+- {7, "In-mux Synchronous Picture-in-Picture presentation"}, -+- {8, "SS Video"}, -+- {0,NULL} -+-}; -+- -+-const VALUE_MAP playback_type_map[] = { -+- {1, "Sequential"}, -+- {2, "Random"}, -+- {3, "Shuffle"}, -+- {0, NULL} -+-}; -+- -+-const VALUE_MAP connection_type_map[] = { -+- {1, "Non-seamless"}, -+- {5, "Seamless"}, -+- {6, "Seamless"}, -+- {0, NULL} -+-}; -+- -+-static const char* -+-_lookup_str(const VALUE_MAP *map, int val) -+-{ -+- int ii; -+- -+- for (ii = 0; map[ii].str; ii++) { -+- if (val == map[ii].value) { -+- return map[ii].str; -+- } -+- } -+- return "?"; -+-} -+- -+-static char * -+-_mk_path(const char *base, const char *sub) -+-{ -+- size_t n1 = strlen(base); -+- size_t n2 = strlen(sub); -+- char *result = (char*)malloc(n1 + n2 + strlen(DIR_SEP) + 1); -+- strcpy(result, base); -+- strcat(result, DIR_SEP); -+- strcat(result, sub); -+- -+- return result; -+-} -+- -+-static void -+-_show_stream(MPLS_STREAM *ss, int level) -+-{ -+- indent_printf(level, "Codec (%04x): %s", ss->coding_type, -+- _lookup_str(codec_map, ss->coding_type)); -+- switch (ss->stream_type) { -+- case 1: -+- indent_printf(level, "PID: %04x", ss->pid); -+- break; -+- -+- case 2: -+- case 4: -+- indent_printf(level, "SubPath Id: %02x", ss->subpath_id); -+- indent_printf(level, "SubClip Id: %02x", ss->subclip_id); -+- indent_printf(level, "PID: %04x", ss->pid); -+- break; -+- -+- case 3: -+- indent_printf(level, "SubPath Id: %02x", ss->subpath_id); -+- indent_printf(level, "PID: %04x", ss->pid); -+- break; -+- -+- default: -+- fprintf(stderr, "unrecognized stream type %02x\n", ss->stream_type); -+- break; -+- }; -+- -+- switch (ss->coding_type) { -+- case 0x01: -+- case 0x02: -+- case 0xea: -+- case 0x1b: -+- indent_printf(level, "Format %02x: %s", ss->format, -+- _lookup_str(video_format_map, ss->format)); -+- indent_printf(level, "Rate %02x: %s", ss->rate, -+- _lookup_str(video_rate_map, ss->rate)); -+- break; -+- -+- case 0x03: -+- case 0x04: -+- case 0x80: -+- case 0x81: -+- case 0x82: -+- case 0x83: -+- case 0x84: -+- case 0x85: -+- case 0x86: -+- case 0xa1: -+- case 0xa2: -+- indent_printf(level, "Format %02x: %s", ss->format, -+- _lookup_str(audio_format_map, ss->format)); -+- indent_printf(level, "Rate %02x: %s", ss->rate, -+- _lookup_str(audio_rate_map, ss->rate)); -+- indent_printf(level, "Language: %s", ss->lang); -+- break; -+- -+- case 0x90: -+- case 0x91: -+- indent_printf(level, "Language: %s", ss->lang); -+- break; -+- -+- case 0x92: -+- indent_printf(level, "Char Code: %02x", ss->char_code); -+- indent_printf(level, "Language: %s", ss->lang); -+- break; -+- -+- default: -+- fprintf(stderr, "unrecognized coding type %02x\n", ss->coding_type); -+- break; -+- }; -+-} -+- -+-static void -+-_show_details(MPLS_PL *pl, int level) -+-{ -+- int ii, jj, kk; -+- -+- for (ii = 0; ii < pl->list_count; ii++) { -+- MPLS_PI *pi; -+- -+- pi = &pl->play_item[ii]; -+- indent_printf(level, "Clip Id %s", pi->clip[0].clip_id); -+- indent_printf(level+1, "Stc Id: %02x", pi->clip[0].stc_id); -+- indent_printf(level+1, "Connection Condition: %s (%02x)", -+- _lookup_str(connection_type_map, pi->connection_condition), -+- pi->connection_condition); -+- indent_printf(level+1, "In-Time: %d", pi->in_time); -+- indent_printf(level+1, "Out-Time: %d", pi->out_time); -+- if (pi->still_mode == 1) { -+- indent_printf(level+1, "Still time: %ds\n", pi->still_time); -+- } -+- if (pi->still_mode == 2) { -+- indent_printf(level+1, "Still time: infinite\n"); -+- } -+- if (pi->angle_count > 1) { -+- for (jj = 1; jj < pi->angle_count; jj++) { -+- indent_printf(level+1, "Angle %d:", jj); -+- indent_printf(level+2, "Clip Id %s", pi->clip[jj].clip_id); -+- indent_printf(level+2, "Stc Id: %02x", pi->clip[jj].stc_id); -+- } -+- } -+- for (jj = 0; jj < pi->stn.num_video; jj++) { -+- indent_printf(level+1, "Video Stream %d:", jj); -+- _show_stream(&pi->stn.video[jj], level + 2); -+- } -+- for (jj = 0; jj < pi->stn.num_audio; jj++) { -+- indent_printf(level+1, "Audio Stream %d:", jj); -+- _show_stream(&pi->stn.audio[jj], level + 2); -+- } -+- for (jj = 0; jj < pi->stn.num_ig; jj++) { -+- indent_printf(level+1, "Interactive Graphics Stream %d:", jj); -+- _show_stream(&pi->stn.ig[jj], level + 2); -+- } -+- for (jj = 0; jj < (pi->stn.num_pg + pi->stn.num_pip_pg); jj++) { -+- if (jj < pi->stn.num_pg) { -+- indent_printf(level+1, "Presentation Graphics Stream %d:", jj); -+- } else { -+- indent_printf(level+1, "PIP Presentation Graphics Stream %d:", jj); -+- } -+- _show_stream(&pi->stn.pg[jj], level + 2); -+- } -+- for (jj = 0; jj < pi->stn.num_secondary_video; jj++) { -+- indent_printf(level+1, "Secondary Video Stream %d:", jj); -+- _show_stream(&pi->stn.secondary_video[jj], level + 2); -+- for (kk = 0; kk < pi->stn.secondary_video[jj].sv_num_secondary_audio_ref; kk++) { -+- indent_printf(level+2, "Secondary Audio Ref %d: %d", kk,pi->stn.secondary_video[jj].sv_secondary_audio_ref[kk]); -+- } -+- for (kk = 0; kk < pi->stn.secondary_video[jj].sv_num_pip_pg_ref; kk++) { -+- indent_printf(level+2, "PIP Presentation Graphic Ref %d: %d", kk,pi->stn.secondary_video[jj].sv_pip_pg_ref[kk]); -+- } -+- } -+- for (jj = 0; jj < pi->stn.num_secondary_audio; jj++) { -+- indent_printf(level+1, "Secondary Audio Stream %d:", jj); -+- _show_stream(&pi->stn.secondary_audio[jj], level + 2); -+- for (kk = 0; kk < pi->stn.secondary_audio[jj].sa_num_primary_audio_ref; kk++) { -+- indent_printf(level+2, "Primary Audio Ref %d: %d", kk,pi->stn.secondary_audio[jj].sa_primary_audio_ref[kk]); -+- } -+- } -+- printf("\n"); -+- } -+-} -+- -+-static void -+-_show_ai(MPLS_PL *pl, int level) -+-{ -+- indent_printf(level, "Playback type: %s (%d)", -+- _lookup_str(playback_type_map, pl->app_info.playback_type), -+- pl->app_info.playback_type); -+- if (pl->app_info.playback_type == 2 || pl->app_info.playback_type == 3) { -+- indent_printf(level+1, "Playback count: %d", pl->app_info.playback_count); -+- } -+-} -+- -+-static void -+-_show_marks(MPLS_PL *pl, int level) -+-{ -+- int ii; -+- -+- indent_printf(level, "PlayMark Count %d", pl->mark_count); -+- for (ii = 0; ii < pl->mark_count; ii++) { -+- MPLS_PI *pi; -+- MPLS_PLM *plm; -+- int min; -+- double sec; -+- -+- plm = &pl->play_mark[ii]; -+- indent_printf(level, "PlayMark %d", ii); -+- indent_printf(level+1, "Type: %02x", plm->mark_type); -+- if (plm->play_item_ref < pl->list_count) { -+- pi = &pl->play_item[plm->play_item_ref]; -+- indent_printf(level+1, "PlayItem: %s", pi->clip[0].clip_id); -+- } else { -+- indent_printf(level+1, "PlayItem: Invalid reference"); -+- } -+- indent_printf(level+1, "Time (ticks): %u", plm->time); -+- min = plm->duration / (45000*60); -+- sec = (double)(plm->duration - min * 45000 * 60) / 45000; -+- indent_printf(level+1, "Duration (mm:ss.ms, ticks): %d:%.2f, %u", -+- min, sec, plm->duration); -+- printf("\n"); -+- } -+-} -+- -+-static void -+-_show_clip_list(MPLS_PL *pl, int level) -+-{ -+- int ii, jj; -+- -+- for (ii = 0; ii < pl->list_count; ii++) { -+- MPLS_PI *pi; -+- -+- pi = &pl->play_item[ii]; -+- if (verbose) { -+- uint32_t duration; -+- -+- duration = pi->out_time - pi->in_time; -+- indent_printf(level, "%s.m2ts -- Duration: %3d:%02d", -+- pi->clip[0].clip_id, -+- duration / (45000 * 60), (duration / 45000) % 60); -+- } else { -+- indent_printf(level, "%s.m2ts", pi->clip[0].clip_id); -+- } -+- if (pi->angle_count > 1) { -+- for (jj = 1; jj < pi->angle_count; jj++) { -+- indent_printf(level+1, "Angle %d: %s.m2ts", jj+1, pi->clip[jj].clip_id); -+- } -+- } -+- } -+- printf("\n"); -+-} -+- -+-static void -+-_show_sub_path(MPLS_SUB *sub, int level) -+-{ -+- int ii; -+- -+- indent_printf(level+1, "Type: %d (%s)", sub->type, _lookup_str(subpath_type_map, sub->type)); -+- indent_printf(level+1, "Repeat: %d", sub->is_repeat); -+- indent_printf(level+1, "Sub playitem count: %d", sub->sub_playitem_count); -+- -+- for (ii = 0; ii < sub->sub_playitem_count; ii++) { -+- MPLS_SUB_PI *pi; -+- -+- pi = &sub->sub_play_item[ii]; -+- -+- if (verbose) { -+- indent_printf(level+1, "Sub playitem %d", ii); -+- indent_printf(level+2, "Clip Id %s", pi->clip[0].clip_id); -+- indent_printf(level+2, "Multi clip: %d", pi->is_multi_clip); -+- indent_printf(level+2, "Clip count: %d", pi->clip_count); -+- indent_printf(level+2, "Connection Condition: %s (%02x)", -+- _lookup_str(connection_type_map, pi->connection_condition), -+- pi->connection_condition); -+- indent_printf(level+2, "In-Time: %d", pi->in_time); -+- indent_printf(level+2, "Out-Time: %d", pi->out_time); -+- indent_printf(level+2, "Sync playitem Id: %d", pi->sync_play_item_id); -+- indent_printf(level+2, "Sync PTS: %d", pi->sync_pts); -+- } else { -+- indent_printf(level+1, "%s.m2ts", pi->clip[0].clip_id); -+- } -+- } -+-} -+- -+-static void -+-_show_pip_metadata_block(MPLS_PIP_METADATA *block, int level) -+-{ -+- int ii; -+- -+- indent_printf(level, "Clip ref: %d", block->clip_ref); -+- indent_printf(level, "Secondary video ref: %d", block->secondary_video_ref); -+- indent_printf(level, "Timeline type: %d", block->timeline_type); -+- indent_printf(level, "Luma key flag: %d", block->luma_key_flag); -+- if (block->luma_key_flag) { -+- indent_printf(level, "Upper limit luma key: %d", block->upper_limit_luma_key); -+- } -+- indent_printf(level, "Trick play flag: %d", block->trick_play_flag); -+- -+- for (ii = 0; ii < block->data_count; ii++) { -+- indent_printf(level, "data block %d:", ii); -+- indent_printf(level+1, "Timestamp: %d", block->data[ii].time); -+- indent_printf(level+1, "Horizontal position %d", block->data[ii].xpos); -+- indent_printf(level+1, "Vertical position: %d", block->data[ii].ypos); -+- indent_printf(level+1, "Scaling factor: %d", block->data[ii].scale_factor); -+- } -+-} -+- -+-static void -+-_show_pip_metadata(MPLS_PL *pl, int level) -+-{ -+- int ii; -+- -+- for (ii = 0; ii < pl->ext_pip_data_count; ii++) { -+- MPLS_PIP_METADATA *data; -+- -+- data = &pl->ext_pip_data[ii]; -+- -+- indent_printf(level, "PiP metadata block %d:", ii); -+- _show_pip_metadata_block(data, level+1); -+- } -+-} -+- -+-static void -+-_show_sub_paths(MPLS_PL *pl, int level) -+-{ -+- int ss; -+- -+- for (ss = 0; ss < pl->sub_count; ss++) { -+- MPLS_SUB *sub; -+- -+- sub = &pl->sub_path[ss]; -+- -+- indent_printf(level, "Sub Path %d:", ss); -+- _show_sub_path(sub, level+1); -+- } -+-} -+- -+-static void -+-_show_sub_paths_ss(MPLS_PL *pl, int level) -+-{ -+- int ss; -+- -+- for (ss = 0; ss < pl->ext_sub_count; ss++) { -+- MPLS_SUB *sub; -+- -+- sub = &pl->ext_sub_path[ss]; -+- -+- indent_printf(level, "Extension Sub Path %d:", ss); -+- _show_sub_path(sub, level+1); -+- } -+-} -+- -+-static uint32_t -+-_pl_duration(MPLS_PL *pl) -+-{ -+- int ii; -+- uint32_t duration = 0; -+- MPLS_PI *pi; -+- -+- for (ii = 0; ii < pl->list_count; ii++) { -+- pi = &pl->play_item[ii]; -+- duration += pi->out_time - pi->in_time; -+- } -+- return duration; -+-} -+- -+-static int -+-_filter_dup(MPLS_PL *pl_list[], int count, MPLS_PL *pl) -+-{ -+- int ii, jj; -+- -+- for (ii = 0; ii < count; ii++) { -+- if (pl->list_count != pl_list[ii]->list_count || -+- _pl_duration(pl) != _pl_duration(pl_list[ii])) { -+- continue; -+- } -+- for (jj = 0; jj < pl->list_count; jj++) { -+- MPLS_PI *pi1, *pi2; -+- -+- pi1 = &pl->play_item[jj]; -+- pi2 = &pl_list[ii]->play_item[jj]; -+- -+- if (memcmp(pi1->clip[0].clip_id, pi2->clip[0].clip_id, 5) != 0 || -+- pi1->in_time != pi2->in_time || -+- pi1->out_time != pi2->out_time) { -+- break; -+- } -+- } -+- if (jj != pl->list_count) { -+- continue; -+- } -+- return 0; -+- } -+- return 1; -+-} -+- -+-static int -+-_find_repeats(MPLS_PL *pl, const char *m2ts) -+-{ -+- int ii, count = 0; -+- -+- for (ii = 0; ii < pl->list_count; ii++) { -+- MPLS_PI *pi; -+- -+- pi = &pl->play_item[ii]; -+- // Ignore titles with repeated segments -+- if (strcmp(pi->clip[0].clip_id, m2ts) == 0) { -+- count++; -+- } -+- } -+- return count; -+-} -+- -+-static int -+-_filter_short(MPLS_PL *pl, unsigned int seconds) -+-{ -+- // Ignore short playlists -+- if (_pl_duration(pl) / 45000 <= seconds) { -+- return 0; -+- } -+- return 1; -+-} -+- -+-static int -+-_filter_repeats(MPLS_PL *pl, int repeats) -+-{ -+- int ii; -+- -+- for (ii = 0; ii < pl->list_count; ii++) { -+- MPLS_PI *pi; -+- -+- pi = &pl->play_item[ii]; -+- // Ignore titles with repeated segments -+- if (_find_repeats(pl, pi->clip[0].clip_id) > repeats) { -+- return 0; -+- } -+- } -+- return 1; -+-} -+- -+-static int clip_list = 0, playlist_info = 0, chapter_marks = 0, sub_paths = 0, pip_metadata = 0; -+-static int repeats = 0, seconds = 0, dups = 0; -+- -+-static MPLS_PL* -+-_process_file(char *name, MPLS_PL *pl_list[], int pl_count) -+-{ -+- MPLS_PL *pl; -+- -+- pl = bd_read_mpls(name); -+- if (pl == NULL) { -+- fprintf(stderr, "Parse failed: %s\n", name); -+- return NULL; -+- } -+- if (seconds) { -+- if (!_filter_short(pl, seconds)) { -+- bd_free_mpls(pl); -+- return NULL; -+- } -+- } -+- if (repeats) { -+- if (!_filter_repeats(pl, repeats)) { -+- bd_free_mpls(pl); -+- return NULL; -+- } -+- } -+- if (dups) { -+- if (!_filter_dup(pl_list, pl_count, pl)) { -+- bd_free_mpls(pl); -+- return NULL; -+- } -+- } -+- if (verbose) { -+- indent_printf(0, -+- "%s -- Num Clips: %3d , Duration: minutes %4u:%02u", -+- basename(name), -+- pl->list_count, -+- _pl_duration(pl) / (45000 * 60), -+- (_pl_duration(pl) / 45000) % 60); -+- _show_ai(pl, 1); -+- } else { -+- indent_printf(0, "%s -- Duration: minutes %4u:%02u", -+- basename(name), -+- _pl_duration(pl) / (45000 * 60), -+- (_pl_duration(pl) / 45000) % 60); -+- } -+- if (playlist_info) { -+- _show_details(pl, 1); -+- } -+- if (chapter_marks) { -+- _show_marks(pl, 1); -+- } -+- if (pip_metadata) { -+- _show_pip_metadata(pl, 1); -+- } -+- if (clip_list) { -+- _show_clip_list(pl, 1); -+- } -+- if (sub_paths) { -+- _show_sub_paths(pl, 1); -+- _show_sub_paths_ss(pl, 1); -+- } -+- return pl; -+-} -+- -+-static void -+-_usage(char *cmd) -+-{ -+- fprintf(stderr, -+-"Usage: %s -vli <mpls file> [<mpls file> ...]\n" -+-"With no options, produces a list of the playlist(s) with durations\n" -+-"Options:\n" -+-" v - Verbose output.\n" -+-" l - Produces a list of the m2ts clips\n" -+-" i - Dumps detailed information about each clip\n" -+-" c - Show chapter marks\n" -+-" p - Show sub paths\n" -+-" P - Show picture-in-picture metadata\n" -+-" r <N> - Filter out titles that have >N repeating clips\n" -+-" d - Filter out duplicate titles\n" -+-" s <seconds> - Filter out short titles\n" -+-" f - Filter combination -r2 -d -s900\n" -+-, cmd); -+- -+- exit(EXIT_FAILURE); -+-} -+- -+-#define OPTS "vlicpPfr:ds:" -+- -+-static int -+-_qsort_str_cmp(const void *a, const void *b) -+-{ -+- const char *stra = *(char * const *)a; -+- const char *strb = *(char * const *)b; -+- -+- return strcmp(stra, strb); -+-} -+- -+-int -+-main(int argc, char *argv[]) -+-{ -+- MPLS_PL *pl; -+- int opt; -+- int ii, pl_ii; -+- MPLS_PL *pl_list[1000]; -+- struct stat st; -+- char *path = NULL; -+- DIR *dir = NULL; -+- -+- do { -+- opt = getopt(argc, argv, OPTS); -+- switch (opt) { -+- case -1: -+- break; -+- -+- case 'v': -+- verbose = 1; -+- break; -+- -+- case 'l': -+- clip_list = 1; -+- break; -+- -+- case 'i': -+- playlist_info = 1; -+- break; -+- -+- case 'c': -+- chapter_marks = 1; -+- break; -+- -+- case 'p': -+- sub_paths = 1; -+- break; -+- -+- case 'P': -+- pip_metadata = 1; -+- break; -+- -+- case 'd': -+- dups = 1; -+- break; -+- -+- case 'r': -+- repeats = atoi(optarg); -+- break; -+- -+- case 'f': -+- repeats = 2; -+- dups = 1; -+- seconds = 900; -+- break; -+- -+- case 's': -+- seconds = atoi(optarg); -+- break; -+- -+- default: -+- _usage(argv[0]); -+- break; -+- } -+- } while (opt != -1); -+- -+- if (optind >= argc) { -+- _usage(argv[0]); -+- } -+- -+- for (pl_ii = 0, ii = optind; pl_ii < 1000 && ii < argc; ii++) { -+- -+- if (stat(argv[ii], &st)) { -+- continue; -+- } -+- dir = NULL; -+- if (S_ISDIR(st.st_mode)) { -+- -+- printf("Directory: %s:\n", argv[ii]); -+- path = _mk_path(argv[ii], PLAYLIST_DIR); -+- if (path == NULL) { -+- fprintf(stderr, "Failed to find playlist path: %s\n", argv[ii]); -+- continue; -+- } -+- dir = opendir(path); -+- if (dir == NULL) { -+- fprintf(stderr, "Failed to open dir: %s\n", path); -+- free(path); -+- continue; -+- } -+- } -+- if (dir != NULL) { -+- char **dirlist = (char**)calloc(10001, sizeof(char*)); -+- struct dirent *ent; -+- int jj = 0; -+- for (ent = readdir(dir); ent != NULL; ent = readdir(dir)) { -+- dirlist[jj++] = strcpy((char*)malloc(strlen(ent->d_name)), ent->d_name); -+- } -+- qsort(dirlist, jj, sizeof(char*), _qsort_str_cmp); -+- for (jj = 0; dirlist[jj] != NULL; jj++) { -+- char *name = NULL; -+- name = _mk_path(path, dirlist[jj]); -+- free(dirlist[jj]); -+- if (stat(name, &st)) { -+- free(name); -+- continue; -+- } -+- if (!S_ISREG(st.st_mode)) { -+- free(name); -+- continue; -+- } -+- pl = _process_file(name, pl_list, pl_ii); -+- free(name); -+- if (pl != NULL) { -+- pl_list[pl_ii++] = pl; -+- } -+- } -+- free(dirlist); -+- free(path); -+- } else { -+- pl = _process_file(argv[ii], pl_list, pl_ii); -+- if (pl != NULL) { -+- pl_list[pl_ii++] = pl; -+- } -+- } -+- } -+- // Cleanup -+- for (ii = 0; ii < pl_ii; ii++) { -+- bd_free_mpls(pl_list[ii]); -+- } -+- return 0; -+-} -+- -+diff --git a/src/examples/util.c b/src/examples/util.c -+deleted file mode 100644 -+index aaa4c46..0000000 -++++ /dev/null -+@@ -1,40 +0,0 @@ -+-/* -+- * This file is part of libbluray -+- * Copyright (C) 2009-2010 John Stebbins -+- * -+- * This library is free software; you can redistribute it and/or -+- * modify it under the terms of the GNU Lesser General Public -+- * License as published by the Free Software Foundation; either -+- * version 2.1 of the License, or (at your option) any later version. -+- * -+- * This library is distributed in the hope that it will be useful, -+- * but WITHOUT ANY WARRANTY; without even the implied warranty of -+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+- * Lesser General Public License for more details. -+- * -+- * You should have received a copy of the GNU Lesser General Public -+- * License along with this library. If not, see -+- * <http://www.gnu.org/licenses/>. -+- */ -+- -+-#include <stdio.h> -+-#include <stdarg.h> -+- -+-#include "util.h" -+- -+-void -+-indent_printf(int level, const char *fmt, ...) -+-{ -+- va_list ap; -+- int ii; -+- -+- for (ii = 0; ii < level; ii++) -+- { -+- printf(" "); -+- } -+- va_start(ap, fmt); -+- vprintf(fmt, ap); -+- va_end(ap); -+- printf("\n"); -+-} -+- -+diff --git a/src/examples/util.h b/src/examples/util.h -+deleted file mode 100644 -+index 144f8ec..0000000 -++++ /dev/null -+@@ -1,43 +0,0 @@ -+-/* -+- * This file is part of libbluray -+- * Copyright (C) 2009-2010 John Stebbins -+- * -+- * This library is free software; you can redistribute it and/or -+- * modify it under the terms of the GNU Lesser General Public -+- * License as published by the Free Software Foundation; either -+- * version 2.1 of the License, or (at your option) any later version. -+- * -+- * This library is distributed in the hope that it will be useful, -+- * but WITHOUT ANY WARRANTY; without even the implied warranty of -+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+- * Lesser General Public License for more details. -+- * -+- * You should have received a copy of the GNU Lesser General Public -+- * License along with this library. If not, see -+- * <http://www.gnu.org/licenses/>. -+- */ -+- -+-#include <stdint.h> -+- -+-#include "util/attributes.h" -+- -+-#if defined( __MINGW32__ ) -+-# undef lseek -+-# define lseek _lseeki64 -+-# undef fseeko -+-# define fseeko fseeko64 -+-# undef ftello -+-# define ftello ftello64 -+-# define flockfile(...) -+-# define funlockfile(...) -+-# define getc_unlocked getc -+-# undef off_t -+-# define off_t off64_t -+-# undef stat -+-# define stat _stati64 -+-# define fstat _fstati64 -+-# define wstat _wstati64 -+-#endif -+- -+-void indent_printf(int level, const char *fmt, ...) BD_ATTR_FORMAT_PRINTF(2,3); -+- +diff --git a/src/file/dir_win32.c b/src/file/dir_win32.c +index 2690658..f42114d 100644 +--- a/src/file/dir_win32.c @@ -74554,32 +50832,19 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + else + priv->handle = -1; +diff --git a/src/file/dirs_win32.c b/src/file/dirs_win32.c -+index 5279ea5..3d07251 100644 ++index e165fea..3d07251 100644 +--- a/src/file/dirs_win32.c ++++ b/src/file/dirs_win32.c -+@@ -36,10 +36,18 @@ ++@@ -36,7 +36,7 @@ + + char *win32_get_font_dir(const char *font_file) + { +- wchar_t wdir[MAX_PATH]; ++ wchar_t wdir[MAX_PATH+1] = {0}; + if (S_OK != SHGetFolderPathW(NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, wdir)) { -+- GetWindowsDirectoryW(wdir, MAX_PATH); -+- wcscat(wdir, L"\\fonts"); -++ int lenght = GetWindowsDirectoryW(wdir, MAX_PATH); -++ if (lenght == 0 || lenght > (MAX_PATH - 8)) { -++ BD_DEBUG(DBG_FILE, "Font directory path too long!\n"); -++ return NULL; -++ } -++ if (!wcscat(wdir, L"\\fonts")) { -++ BD_DEBUG(DBG_FILE, "Could not construct font directory path!\n"); -++ return NULL; -++ } -++ -+ } -+ -+ int len = WideCharToMultiByte (CP_UTF8, 0, wdir, -1, NULL, 0, NULL, NULL); -+@@ -59,7 +67,7 @@ char *file_get_config_home(void) ++ int lenght = GetWindowsDirectoryW(wdir, MAX_PATH); ++ if (lenght == 0 || lenght > (MAX_PATH - 8)) { ++@@ -67,7 +67,7 @@ char *file_get_config_home(void) + + char *file_get_data_home(void) + { @@ -74588,7 +50853,7 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + + /* Get the "Application Data" folder for the user */ + if (S_OK == SHGetFolderPathW(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, -+@@ -84,7 +92,7 @@ char *file_get_cache_home(void) ++@@ -92,7 +92,7 @@ char *file_get_cache_home(void) + const char *file_get_config_system(const char *dir) + { + static char *appdir = NULL; @@ -74619,44 +50884,11 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + HMODULE hModule; + wchar_t wpath[MAX_PATH]; + -+diff --git a/src/file/file.c b/src/file/file.c -+index 15edfe0..2f85248 100644 -+--- a/src/file/file.c -++++ b/src/file/file.c -+@@ -52,6 +52,10 @@ int file_mkdirs(const char *path) -+ char *end = dir; -+ char *p; -+ -++ if (!dir) { -++ return -1; -++ } -++ -+ /* strip file name */ -+ if (!(end = strrchr(end, DIR_SEP_CHAR))) { -+ X_FREE(dir); -+diff --git a/src/file/file_posix.c b/src/file/file_posix.c -+index 753a8ce..2a79f6f 100644 -+--- a/src/file/file_posix.c -++++ b/src/file/file_posix.c -+@@ -38,6 +38,13 @@ -+ #include <sys/stat.h> -+ #include <fcntl.h> -+ -++#ifdef __ANDROID__ -++# undef lseek -++# define lseek lseek64 -++# undef off_t -++# define off_t off64_t -++#endif -++ -+ static void _file_close(BD_FILE_H *file) -+ { -+ if (file) { +diff --git a/src/file/file_win32.c b/src/file/file_win32.c -+index 5eb52d7..c0f48e4 100644 ++index d9845fb..b4fb7ad 100644 +--- a/src/file/file_win32.c ++++ b/src/file/file_win32.c -+@@ -97,9 +97,9 @@ static BD_FILE_H *_file_open(const char* filename, const char *mode) ++@@ -107,9 +107,9 @@ static BD_FILE_H *_file_open(const char* filename, const char *mode) + { + BD_FILE_H *file; + FILE *fp; @@ -74668,7 +50900,7 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + !MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, mode, -1, wmode, 8)) { + + BD_DEBUG(DBG_FILE, "Error opening file %s\n", filename); -+@@ -112,6 +112,9 @@ static BD_FILE_H *_file_open(const char* filename, const char *mode) ++@@ -122,6 +122,9 @@ static BD_FILE_H *_file_open(const char* filename, const char *mode) + return NULL; + } + @@ -74678,2210 +50910,8 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + file = calloc(1, sizeof(BD_FILE_H)); + if (!file) { + BD_DEBUG(DBG_FILE | DBG_CRIT, "Error opening file %s (out of memory)\n", filename); -+diff --git a/src/file/mount.c b/src/file/mount.c -+index 6382d8b..7575f89 100644 -+--- a/src/file/mount.c -++++ b/src/file/mount.c -+@@ -33,6 +33,7 @@ -+ -+ char *mount_get_mountpoint(const char *device_path) -+ { -++#ifndef __ANDROID__ -+ #ifdef HAVE_MNTENT_H -+ struct stat st; -+ if (stat (device_path, &st) ) { -+@@ -62,6 +63,7 @@ char *mount_get_mountpoint(const char *device_path) -+ endmntent (f); -+ } -+ #endif /* HAVE_MNTENT_H */ -++#endif /* __ANDROID__ */ -+ -+ return str_dup(device_path); -+ } -+diff --git a/src/libbluray/bdj/bdj.c b/src/libbluray/bdj/bdj.c -+index 3465c69..23d944a 100644 -+--- a/src/libbluray/bdj/bdj.c -++++ b/src/libbluray/bdj/bdj.c -+@@ -26,6 +26,7 @@ -+ -+ #include "native/register_native.h" -+ -++#include "file/file.h" -+ #include "file/dirs.h" -+ #include "file/dl.h" -+ #include "util/strutl.h" -+@@ -41,9 +42,6 @@ -+ #ifdef _WIN32 -+ #include <windows.h> -+ #include <winreg.h> -+-#define DIR_SEP "\\" -+-#else -+-#define DIR_SEP "/" -+ #endif -+ -+ #ifdef HAVE_BDJ_J2ME -+@@ -67,7 +65,7 @@ static void *_load_jvm_win32(const char **p_java_home) -+ -+ wchar_t buf_loc[4096] = L"SOFTWARE\\JavaSoft\\Java Runtime Environment\\"; -+ wchar_t buf_vers[128]; -+- -++ wchar_t java_path[4096] = L""; -+ char strbuf[256]; -+ -+ LONG r; -+@@ -77,14 +75,14 @@ static void *_load_jvm_win32(const char **p_java_home) -+ -+ r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buf_loc, 0, KEY_READ, &hkey); -+ if (r != ERROR_SUCCESS) { -+- BD_DEBUG(DBG_BDJ | DBG_CRIT, "Error opening registry key SOFTWARE\\JavaSoft\\Java Runtime Environment\\"); -++ BD_DEBUG(DBG_BDJ | DBG_CRIT, "Error opening registry key SOFTWARE\\JavaSoft\\Java Runtime Environment\\\n"); -+ return NULL; -+ } -+ -+ r = RegQueryValueExW(hkey, L"CurrentVersion", NULL, &lType, (LPBYTE)buf_vers, &dSize); -+ RegCloseKey(hkey); -+ if (r != ERROR_SUCCESS) { -+- BD_DEBUG(DBG_BDJ | DBG_CRIT, "CurrentVersion registry value not found"); -++ BD_DEBUG(DBG_BDJ | DBG_CRIT, "CurrentVersion registry value not found\n"); -+ return NULL; -+ } -+ -+@@ -97,7 +95,7 @@ static void *_load_jvm_win32(const char **p_java_home) -+ dSize = sizeof(buf_loc); -+ r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buf_loc, 0, KEY_READ, &hkey); -+ if (r != ERROR_SUCCESS) { -+- BD_DEBUG(DBG_BDJ | DBG_CRIT, "Error opening JRE version-specific registry key"); -++ BD_DEBUG(DBG_BDJ | DBG_CRIT, "Error opening JRE version-specific registry key\n"); -+ return NULL; -+ } -+ -+@@ -108,6 +106,9 @@ static void *_load_jvm_win32(const char **p_java_home) -+ WideCharToMultiByte(CP_UTF8, 0, buf_loc, -1, java_home, sizeof(java_home), NULL, NULL); -+ *p_java_home = java_home; -+ BD_DEBUG(DBG_BDJ, "JavaHome: %s\n", java_home); -++ -++ wcscat(java_path, buf_loc); -++ wcscat(java_path, L"\\bin"); -+ } -+ -+ dSize = sizeof(buf_loc); -+@@ -115,11 +116,13 @@ static void *_load_jvm_win32(const char **p_java_home) -+ RegCloseKey(hkey); -+ -+ if (r != ERROR_SUCCESS) { -+- BD_DEBUG(DBG_BDJ | DBG_CRIT, "RuntimeLib registry value not found"); -++ BD_DEBUG(DBG_BDJ | DBG_CRIT, "RuntimeLib registry value not found\n"); -+ return NULL; -+ } -+ -++ SetDllDirectoryW(java_path); -+ void *result = LoadLibraryW(buf_loc); -++ SetDllDirectoryW(NULL); -+ -+ WideCharToMultiByte(CP_UTF8, 0, buf_loc, -1, strbuf, sizeof(strbuf), NULL, NULL); -+ if (!result) { -+@@ -132,10 +135,43 @@ static void *_load_jvm_win32(const char **p_java_home) -+ } -+ #endif -+ -++#ifdef _WIN32 -++static inline char *_utf8_to_cp(const char *utf8) -++{ -++ int wlen = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0); -++ if (wlen == 0) { -++ return NULL; -++ } -++ -++ wchar_t *wide = (wchar_t *)malloc(wlen * sizeof(wchar_t)); -++ if (!wide) { -++ return NULL; -++ } -++ MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wide, wlen); -++ -++ size_t len = WideCharToMultiByte(CP_ACP, 0, wide, -1, NULL, 0, NULL, NULL); -++ if (len == 0) { -++ X_FREE(wide); -++ return NULL; -++ } -++ -++ char *out = (char *)malloc(len); -++ if (out != NULL) { -++ WideCharToMultiByte(CP_ACP, 0, wide, -1, out, len, NULL, NULL); -++ } -++ X_FREE(wide); -++ return out; -++} -++#endif -++ -+ static void *_jvm_dlopen(const char *java_home, const char *jvm_dir, const char *jvm_lib) -+ { -+ if (java_home) { -+ char *path = str_printf("%s/%s/%s", java_home, jvm_dir, jvm_lib); -++ if (!path) { -++ BD_DEBUG(DBG_CRIT, "out of memory\n"); -++ return NULL; -++ } -+ BD_DEBUG(DBG_BDJ, "Opening %s ...\n", path); -+ void *h = dl_dlopen(path, NULL); -+ X_FREE(path); -+@@ -208,11 +244,17 @@ static void *_load_jvm(const char **p_java_home) -+ -+ static int _can_read_file(const char *fn) -+ { -+- FILE *fp = fopen(fn, "rb"); -++ BD_FILE_H *fp; -++ -++ if (!fn) { -++ return 0; -++ } -++ -++ fp = file_open(fn, "rb"); -+ if (fp) { -+- char b; -+- int result = (int)fread(&b, 1, 1, fp); -+- fclose(fp); -++ uint8_t b; -++ int result = (int)file_read(fp, &b, 1); -++ file_close(fp); -+ if (result == 1) { -+ return 1; -+ } -+@@ -460,6 +502,11 @@ static int _create_jvm(void *jvm_lib, const char *java_home, const char *jar_fil -+ } -+ -+ JavaVMOption* option = calloc(1, sizeof(JavaVMOption) * 20); -++ if (!option) { -++ BD_DEBUG(DBG_CRIT, "out of memory\n"); -++ return 0; -++ } -++ -+ int n = 0; -+ JavaVMInitArgs args; -+ option[n++].optionString = str_dup ("-Dawt.toolkit=java.awt.BDToolkit"); -+@@ -499,6 +546,17 @@ static int _create_jvm(void *jvm_lib, const char *java_home, const char *jar_fil -+ args.options = option; -+ args.ignoreUnrecognized = JNI_FALSE; // don't ignore unrecognized options -+ -++#ifdef _WIN32 -++ /* ... in windows, JVM options are not UTF8 but current system code page ... */ -++ /* luckily, most BD-J options can be passed in as java strings later. But, not class path. */ -++ int ii; -++ for (ii = 0; ii < n; ii++) { -++ char *tmp = _utf8_to_cp(option[ii].optionString); -++ X_FREE(option[ii].optionString); -++ option[ii].optionString = tmp; -++ } -++#endif -++ -+ int result = JNI_CreateJavaVM_fp(jvm, (void**) env, &args); -+ -+ while (--n >= 0) { -+@@ -534,16 +592,22 @@ BDJAVA* bdj_open(const char *path, struct bluray *bd, -+ return 0; -+ } -+ -++ BDJAVA* bdjava = calloc(1, sizeof(BDJAVA)); -++ if (!bdjava) { -++ dl_dlclose(jvm_lib); -++ return NULL; -++ } -++ -+ JNIEnv* env = NULL; -+ JavaVM *jvm = NULL; -+ if (!_find_jvm(jvm_lib, &env, &jvm) && -+ !_create_jvm(jvm_lib, java_home, jar_file, &env, &jvm)) { -+ -++ X_FREE(bdjava); -+ dl_dlclose(jvm_lib); -+ return NULL; -+ } -+ -+- BDJAVA* bdjava = calloc(1, sizeof(BDJAVA)); -+ bdjava->h_libjvm = jvm_lib; -+ bdjava->jvm = jvm; -+ -+diff --git a/src/libbluray/bdj/bdj.h b/src/libbluray/bdj/bdj.h -+index 45fbfc5..f6cd97b 100644 -+--- a/src/libbluray/bdj/bdj.h -++++ b/src/libbluray/bdj/bdj.h -+@@ -45,10 +45,10 @@ typedef enum { -+ } BDJ_EVENT; -+ -+ typedef struct { -+- char *persistent_root; -+- char *cache_root; -++ char *persistent_root; /* BD-J Xlet persistent storage */ -++ char *cache_root; /* BD-J binding unit data area */ -+ -+- char *classpath; -++ char *classpath; /* BD-J implementation class path (location of libbluray.jar) */ -+ } BDJ_STORAGE; -+ -+ typedef struct bdjava_s BDJAVA; -+diff --git a/src/libbluray/bdj/build.xml b/src/libbluray/bdj/build.xml -+index c2764f7..938cd44 100644 -+--- a/src/libbluray/bdj/build.xml -++++ b/src/libbluray/bdj/build.xml -+@@ -7,6 +7,7 @@ -+ <property name="build" location="build"/> -+ <property name="dist" location="../../.libs"/> -+ <property name="src_awt" value=""/> -++ <property name="src_asm" value="../../../contrib/asm/src/"/> -+ <property name="bootclasspath" value=""/> -+ <property name="version" value=""/> -+ -+@@ -18,6 +19,12 @@ -+ -+ <target name="compile" depends="init" -+ description="compile the source " > -++ <javac srcdir="${src_asm}" destdir="${build}" debug="yes" -++ bootclasspath="${bootclasspath}" -++ source="1.5" target="1.5"> -++ <compilerarg value="-XDignore.symbol.file"/> -++ <compilerarg value="-Xlint:-deprecation"/> -++ </javac> -+ <javac srcdir="${src}${src_awt}" destdir="${build}" debug="yes" -+ bootclasspath="${bootclasspath}" -+ source="1.4" target="1.4"> -+diff --git a/src/libbluray/bdj/java-j2se/java/awt/BDGraphics.java b/src/libbluray/bdj/java-j2se/java/awt/BDGraphics.java -+index 54c24e5..77ce66e 100644 -+--- a/src/libbluray/bdj/java-j2se/java/awt/BDGraphics.java -++++ b/src/libbluray/bdj/java-j2se/java/awt/BDGraphics.java -+@@ -53,6 +53,7 @@ class BDGraphics extends BDGraphicsBase { -+ -+ public java.awt.font.FontRenderContext getFontRenderContext() -+ { -++ logger.unimplemented("getFontRenderContext"); -+ return null; -+ } -+ public void setPaint(Paint p) { -+diff --git a/src/libbluray/bdj/java/com/aacsla/bluray/online/ContentAttribute.java b/src/libbluray/bdj/java/com/aacsla/bluray/online/ContentAttribute.java -+index fbfa45d..34f59e4 100644 -+--- a/src/libbluray/bdj/java/com/aacsla/bluray/online/ContentAttribute.java -++++ b/src/libbluray/bdj/java/com/aacsla/bluray/online/ContentAttribute.java -+@@ -27,10 +27,33 @@ public class ContentAttribute { -+ } -+ -+ public byte[] getContentCertID() { -++ byte[] id = getContentCertID("AACS" + File.separator + "Content000.cer"); -++ if (id != null) { -++ return id; -++ } -++ -++ id = getContentCertID("MAKEMKV" + File.separator + "AACS" + File.separator + "Content000.cer"); -++ if (id != null) { -++ return id; -++ } -++ -++ id = getContentCertID("ANY!" + File.separator + "Content000.cer"); -++ if (id != null) { -++ return id; -++ } -++ -++ return new byte[6]; -++ } -++ -++ private byte[] getContentCertID(String file) { -+ FileInputStream is = null; -+ try { -+ is = new FileInputStream( -+- System.getProperty("bluray.vfs.root") + File.separator + "AACS/Content000.cer"); -++ System.getProperty("bluray.vfs.root") + File.separator + file); -++ } catch (Exception e) { -++ return null; -++ } -++ try { -+ if (is.skip(14) != 14) -+ return null; -+ byte[] bytes = new byte[6]; -+diff --git a/src/libbluray/bdj/java/java/awt/BDFontMetrics.java b/src/libbluray/bdj/java/java/awt/BDFontMetrics.java -+index d2a91dc..fdcda44 100644 -+--- a/src/libbluray/bdj/java/java/awt/BDFontMetrics.java -++++ b/src/libbluray/bdj/java/java/awt/BDFontMetrics.java -+@@ -192,7 +192,12 @@ public class BDFontMetrics extends sun.font.FontDesignMetrics { -+ } -+ -+ static synchronized String[] getFontList() { -+- init(); -++ try { -++ init(); -++ } catch (Throwable t) { -++ System.err.println("getFontList() failed: " + t); -++ return new String[0]; -++ } -+ -+ ArrayList fontNames = new ArrayList(); -+ -+diff --git a/src/libbluray/bdj/java/java/awt/BDGraphicsBase.java b/src/libbluray/bdj/java/java/awt/BDGraphicsBase.java -+index 0c7d403..f7e60f7 100644 -+--- a/src/libbluray/bdj/java/java/awt/BDGraphicsBase.java -++++ b/src/libbluray/bdj/java/java/awt/BDGraphicsBase.java -+@@ -306,7 +306,7 @@ abstract class BDGraphicsBase extends Graphics2D implements ConstrainableGraphic -+ Rectangle rect = new Rectangle(x, y, length, 1); -+ rect = actualClip.intersection(rect); -+ -+- if (rect.width <= 0 || rect.height <= 0 || rect.x < 0 || rect.y < 0) { -++ if (rect.width <= 0 || rect.height <= 0 || rect.x < 0 || rect.y < 0 || backBuffer == null) { -+ return; -+ } -+ -+@@ -364,7 +364,7 @@ abstract class BDGraphicsBase extends Graphics2D implements ConstrainableGraphic -+ Rectangle rect = new Rectangle(x, y, length, 1); -+ rect = actualClip.intersection(rect); -+ -+- if (rect.width <= 0 || rect.height <= 0 || rect.x < 0 || rect.y < 0) { -++ if (rect.width <= 0 || rect.height <= 0 || rect.x < 0 || rect.y < 0 || backBuffer == null) { -+ return; -+ } -+ -+@@ -458,7 +458,7 @@ abstract class BDGraphicsBase extends Graphics2D implements ConstrainableGraphic -+ y += originY; -+ Rectangle rect = new Rectangle(x, y, w, h); -+ rect = actualClip.intersection(rect); -+- if (rect.isEmpty()) { -++ if (rect.isEmpty() || backBuffer == null) { -+ return; -+ } -+ x = rect.x; -+@@ -572,7 +572,7 @@ abstract class BDGraphicsBase extends Graphics2D implements ConstrainableGraphic -+ Rectangle rect = new Rectangle(x, y, w, h); -+ rect = actualClip.intersection(rect); -+ -+- if (rect.width <= 0 || rect.height <= 0) { -++ if (rect.width <= 0 || rect.height <= 0 || backBuffer == null) { -+ return; -+ } -+ -+diff --git a/src/libbluray/bdj/java/java/awt/BDImageConsumer.java b/src/libbluray/bdj/java/java/awt/BDImageConsumer.java -+index 59e2af3..a076873 100644 -+--- a/src/libbluray/bdj/java/java/awt/BDImageConsumer.java -++++ b/src/libbluray/bdj/java/java/awt/BDImageConsumer.java -+@@ -25,7 +25,7 @@ import java.awt.image.ImageObserver; -+ import java.awt.image.ImageConsumer; -+ import java.awt.image.ColorModel; -+ -+-public class BDImageConsumer extends BDImage implements ImageConsumer { -++class BDImageConsumer extends BDImage implements ImageConsumer { -+ private Hashtable properties; -+ private ImageProducer producer; -+ private int status; -+diff --git a/src/libbluray/bdj/java/java/awt/BDToolkitBase.java b/src/libbluray/bdj/java/java/awt/BDToolkitBase.java -+index e210dea..0f5e3e0 100644 -+--- a/src/libbluray/bdj/java/java/awt/BDToolkitBase.java -++++ b/src/libbluray/bdj/java/java/awt/BDToolkitBase.java -+@@ -124,6 +124,10 @@ abstract class BDToolkitBase extends Toolkit { -+ } -+ -+ public Image getImage(String filename) { -++ if (BDJXletContext.getCurrentContext() == null) { -++ logger.error("getImage(): no context " + Logger.dumpStack()); -++ } -++ -+ if (cachedImages.containsKey(filename)) -+ return (Image)cachedImages.get(filename); -+ Image newImage = createImage(filename); -+@@ -133,6 +137,10 @@ abstract class BDToolkitBase extends Toolkit { -+ } -+ -+ public Image getImage(URL url) { -++ if (BDJXletContext.getCurrentContext() == null) { -++ logger.error("getImage(): no context " + Logger.dumpStack()); -++ } -++ -+ if (cachedImages.containsKey(url)) -+ return (Image)cachedImages.get(url); -+ Image newImage = createImage(url); -+@@ -142,6 +150,10 @@ abstract class BDToolkitBase extends Toolkit { -+ } -+ -+ public Image createImage(String filename) { -++ if (BDJXletContext.getCurrentContext() == null) { -++ logger.error("createImage(): no context " + Logger.dumpStack()); -++ } -++ -+ if (!new File(filename).isAbsolute()) { -+ String home = BDJXletContext.getCurrentXletHome(); -+ if (home != null) { -+@@ -161,6 +173,9 @@ abstract class BDToolkitBase extends Toolkit { -+ } -+ -+ public Image createImage(URL url) { -++ if (BDJXletContext.getCurrentContext() == null) { -++ logger.error("createImage(): no context " + Logger.dumpStack()); -++ } -+ ImageProducer ip = new URLImageSource(url); -+ Image newImage = createImage(ip); -+ return newImage; -+@@ -169,12 +184,20 @@ abstract class BDToolkitBase extends Toolkit { -+ public Image createImage(byte[] imagedata, -+ int imageoffset, -+ int imagelength) { -++ -++ if (BDJXletContext.getCurrentContext() == null) { -++ logger.error("createImage(): no context " + Logger.dumpStack()); -++ } -++ -+ ImageProducer ip = new ByteArrayImageSource(imagedata, imageoffset, imagelength); -+ Image newImage = createImage(ip); -+ return newImage; -+ } -+ -+ public Image createImage(ImageProducer producer) { -++ if (BDJXletContext.getCurrentContext() == null) { -++ logger.error("createImage(): no context " + Logger.dumpStack()); -++ } -+ return new BDImageConsumer(producer); -+ } -+ -+@@ -243,7 +266,7 @@ abstract class BDToolkitBase extends Toolkit { -+ } -+ } -+ -+- logger.warning("getSystemEventQueue(): no context"); -++ logger.warning("getSystemEventQueue(): no context from:" + logger.dumpStack()); -+ return eventQueue; -+ } -+ } -+diff --git a/src/libbluray/bdj/java/java/awt/BDWindowGraphics.java b/src/libbluray/bdj/java/java/awt/BDWindowGraphics.java -+index 743f441..26e7248 100644 -+--- a/src/libbluray/bdj/java/java/awt/BDWindowGraphics.java -++++ b/src/libbluray/bdj/java/java/awt/BDWindowGraphics.java -+@@ -39,6 +39,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void clearRect(int x, int y, int w, int h) { -++ if (window == null) return; -+ synchronized (window) { -+ super.clearRect(x, y, w, h); -+ window.notifyChanged(); -+@@ -46,6 +47,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void fillRect(int x, int y, int w, int h) { -++ if (window == null) return; -+ synchronized (window) { -+ super.fillRect(x, y, w, h); -+ window.notifyChanged(); -+@@ -53,6 +55,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void drawRect(int x, int y, int w, int h) { -++ if (window == null) return; -+ synchronized (window) { -+ super.drawRect(x, y, w, h); -+ window.notifyChanged(); -+@@ -60,6 +63,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void drawLine(int x1, int y1, int x2, int y2) { -++ if (window == null) return; -+ synchronized (window) { -+ super.drawLine(x1, y1, x2, y2); -+ window.notifyChanged(); -+@@ -67,6 +71,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void copyArea(int x, int y, int w, int h, int dx, int dy) { -++ if (window == null) return; -+ synchronized (window) { -+ super.copyArea(x, y, w, h, dx, dy); -+ window.notifyChanged(); -+@@ -74,6 +79,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void drawPolyline(int xPoints[], int yPoints[], int nPoints) { -++ if (window == null) return; -+ synchronized (window) { -+ super.drawPolyline(xPoints, yPoints, nPoints); -+ window.notifyChanged(); -+@@ -81,6 +87,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void drawPolygon(int xPoints[], int yPoints[], int nPoints) { -++ if (window == null) return; -+ synchronized (window) { -+ super.drawPolygon(xPoints, yPoints, nPoints); -+ window.notifyChanged(); -+@@ -88,6 +95,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void fillPolygon(int xPoints[], int yPoints[], int nPoints) { -++ if (window == null) return; -+ synchronized (window) { -+ super.fillPolygon(xPoints, yPoints, nPoints); -+ window.notifyChanged(); -+@@ -95,6 +103,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void drawOval(int x, int y, int w, int h) { -++ if (window == null) return; -+ synchronized (window) { -+ super.drawOval(x, y, w, h); -+ window.notifyChanged(); -+@@ -102,6 +111,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void fillOval(int x, int y, int w, int h) { -++ if (window == null) return; -+ synchronized (window) { -+ super.fillOval(x, y, w, h); -+ window.notifyChanged(); -+@@ -109,6 +119,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void drawArc(int x, int y, int w, int h, int startAngle, int endAngle) { -++ if (window == null) return; -+ synchronized (window) { -+ super.drawArc(x, y, w, h, startAngle, endAngle); -+ window.notifyChanged(); -+@@ -116,6 +127,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void fillArc(int x, int y, int w, int h, int startAngle, int endAngle) { -++ if (window == null) return; -+ synchronized (window) { -+ super.fillArc(x, y, w, h, startAngle, endAngle); -+ window.notifyChanged(); -+@@ -123,6 +135,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void drawRoundRect(int x, int y, int w, int h, int arcWidth, int arcHeight) { -++ if (window == null) return; -+ synchronized (window) { -+ super.drawRoundRect(x, y, w, h, arcWidth, arcHeight); -+ window.notifyChanged(); -+@@ -130,6 +143,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void fillRoundRect(int x, int y, int w, int h, int arcWidth, int arcHeight) { -++ if (window == null) return; -+ synchronized (window) { -+ super.fillRoundRect(x, y, w, h, arcWidth, arcHeight); -+ window.notifyChanged(); -+@@ -137,6 +151,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ protected void drawStringN(long ftFace, String string, int x, int y, int rgb) { -++ if (window == null) return; -+ synchronized (window) { -+ super.drawStringN(ftFace, string, x, y, rgb); -+ window.notifyChanged(); -+@@ -154,6 +169,8 @@ public class BDWindowGraphics extends BDGraphics { -+ boolean flipX, boolean flipY, -+ Color bg, ImageObserver observer) { -+ -++ if (window == null) return true; -++ -+ synchronized (window) { -+ boolean complete = super.drawImageN( -+ img, dx, dy, dw, dh, sx, sy, sw, sh, -+diff --git a/src/libbluray/bdj/java/java/awt/Font.java b/src/libbluray/bdj/java/java/awt/Font.java -+index a126bc5..a952599 100644 -+--- a/src/libbluray/bdj/java/java/awt/Font.java -++++ b/src/libbluray/bdj/java/java/awt/Font.java -+@@ -198,6 +198,9 @@ public class Font implements java.io.Serializable { -+ public Font deriveFont(int style, int size) { -+ return new Font(name, style, size, fontFile, family); -+ } -++ public Font deriveFont(int style, float size) { -++ return new Font(name, style, (int)size, fontFile, family); -++ } -+ -+ /* constructor */ -+ private Font(String name, int style, int size, File fontFile, String family) { -+diff --git a/src/libbluray/bdj/java/javax/media/MediaLocator.java b/src/libbluray/bdj/java/javax/media/MediaLocator.java -+index a182e8d..245ac54 100644 -+--- a/src/libbluray/bdj/java/javax/media/MediaLocator.java -++++ b/src/libbluray/bdj/java/javax/media/MediaLocator.java -+@@ -25,11 +25,11 @@ import java.net.URL; -+ -+ public class MediaLocator implements Serializable -+ { -+- public MediaLocator(URL url) { -++ public MediaLocator(URL url) { -+ this(url.toExternalForm()); -+ } -+ -+- public MediaLocator(String locatorString) { -++ public MediaLocator(String locatorString) { -+ int index = locatorString.indexOf(":"); -+ if (index <= 0) -+ throw new IllegalArgumentException("Bad locator string."); -+@@ -56,7 +56,7 @@ public class MediaLocator implements Serializable -+ public String toExternalForm() { -+ return protocol + ":" + remainder; -+ } -+- -++ -+ private String protocol = ""; -+ private String remainder = ""; -+ -+diff --git a/src/libbluray/bdj/java/javax/tv/graphics/TVContainer.java b/src/libbluray/bdj/java/javax/tv/graphics/TVContainer.java -+index e036884..09971b6 100644 -+--- a/src/libbluray/bdj/java/javax/tv/graphics/TVContainer.java -++++ b/src/libbluray/bdj/java/javax/tv/graphics/TVContainer.java -+@@ -20,9 +20,10 @@ package javax.tv.graphics; -+ -+ import java.awt.Container; -+ import javax.tv.xlet.XletContext; -+-import org.havi.ui.HScene; -+ import org.havi.ui.HSceneFactory; -+ -++import org.videolan.BDJXletContext; -++ -+ public class TVContainer { -+ public static Container getRootContainer(XletContext context) -+ { -+@@ -30,7 +31,15 @@ public class TVContainer { -+ throw new NullPointerException(); -+ } -+ -+- HScene scene = HSceneFactory.getInstance().getDefaultHScene(); -+- return scene; -++ if (!(context instanceof BDJXletContext) || (BDJXletContext)context != BDJXletContext.getCurrentContext()) { -++ org.videolan.Logger.getLogger(TVContainer.class.getName()).error("wrong context"); -++ } -++ -++ /* GEM: return instance of org.havi.ui.HScene or NULL */ -++ HSceneFactory sf = HSceneFactory.getInstance(); -++ if (sf != null) { -++ return sf.getDefaultHScene(); -++ } -++ return null; -+ } -+ } -+diff --git a/src/libbluray/bdj/java/javax/tv/locator/LocatorImpl.java b/src/libbluray/bdj/java/javax/tv/locator/LocatorImpl.java -+index e14825c..a87269a 100644 -+--- a/src/libbluray/bdj/java/javax/tv/locator/LocatorImpl.java -++++ b/src/libbluray/bdj/java/javax/tv/locator/LocatorImpl.java -+@@ -24,7 +24,7 @@ public class LocatorImpl implements Locator { -+ this.url = url; -+ } -+ -+- public boolean hasMultipleTransformations() { -++ public boolean hasMultipleTransformations() { -+ return false; -+ } -+ -+diff --git a/src/libbluray/bdj/java/javax/tv/service/SIElement.java b/src/libbluray/bdj/java/javax/tv/service/SIElement.java -+index c2a0262..16140de 100644 -+--- a/src/libbluray/bdj/java/javax/tv/service/SIElement.java -++++ b/src/libbluray/bdj/java/javax/tv/service/SIElement.java -+@@ -26,7 +26,7 @@ public interface SIElement extends SIRetrievable -+ public Locator getLocator(); -+ -+ public boolean equals(Object obj); -+- -++ -+ public int hashCode(); -+ -+ public ServiceInformationType getServiceInformationType(); -+diff --git a/src/libbluray/bdj/java/javax/tv/service/SIManagerImpl.java b/src/libbluray/bdj/java/javax/tv/service/SIManagerImpl.java -+index 4016876..f9d4a32 100644 -+--- a/src/libbluray/bdj/java/javax/tv/service/SIManagerImpl.java -++++ b/src/libbluray/bdj/java/javax/tv/service/SIManagerImpl.java -+@@ -29,6 +29,7 @@ import javax.tv.service.navigation.ServiceListImpl; -+ import javax.tv.service.transport.Transport; -+ import javax.tv.service.transport.TransportImpl; -+ -++import org.bluray.net.BDLocator; -+ import org.bluray.ti.TitleImpl; -+ import org.videolan.Libbluray; -+ -+@@ -82,6 +83,15 @@ public class SIManagerImpl extends SIManager { -+ } -+ -+ public Service getService(Locator locator) throws InvalidLocatorException, SecurityException { -++ -++ BDLocator bdLocator = null; -++ try { -++ bdLocator = new BDLocator(locator.toExternalForm()); -++ } catch (org.davic.net.InvalidLocatorException e) { -++ System.err.println("invalid locator: " + locator.toExternalForm() + "\n" + org.videolan.Logger.dumpStack(e)); -++ throw new javax.tv.locator.InvalidLocatorException(locator); -++ } -++ -+ return titles.findService(locator); -+ } -+ -+diff --git a/src/libbluray/bdj/java/javax/tv/service/navigation/SIElementFilter.java b/src/libbluray/bdj/java/javax/tv/service/navigation/SIElementFilter.java -+index fdfa128..f0dc97c 100644 -+--- a/src/libbluray/bdj/java/javax/tv/service/navigation/SIElementFilter.java -++++ b/src/libbluray/bdj/java/javax/tv/service/navigation/SIElementFilter.java -+@@ -1,6 +1,7 @@ -+ /* -+ * This file is part of libbluray -+ * Copyright (C) 2010 William Hahne -++ * Copyright (C) 2015 Petri Hintukainen -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+@@ -25,9 +26,21 @@ import javax.tv.service.SIElement; -+ import javax.tv.service.SIRequest; -+ import javax.tv.service.SIRequestorImpl; -+ -++import org.bluray.net.BDLocator; -++ -+ public final class SIElementFilter extends ServiceFilter -+ { -+ public SIElementFilter(SIElement element) throws FilterNotSupportedException { -++ if (element == null) -++ throw new NullPointerException(); -++ -++ try { -++ new BDLocator(element.getLocator().toExternalForm()); -++ } catch (Exception e) { -++ System.err.println("Invalid SI element: " + e + " at " + org.videolan.Logger.dumpStack(e)); -++ throw new FilterNotSupportedException(); -++ } -++ -+ this.element = element; -+ } -+ -+@@ -37,9 +50,9 @@ public final class SIElementFilter extends ServiceFilter -+ -+ public boolean accept(Service service) { -+ SIRequestorImpl requestor = new SIRequestorImpl(); -+- -++ -+ SIRequest req = service.retrieveDetails(requestor); -+- -++ -+ // TODO: This may be a bit excessive -+ int timeout = 0; -+ while (!requestor.getResponse() && timeout < 1000) { -+@@ -48,27 +61,27 @@ public final class SIElementFilter extends ServiceFilter -+ } catch (InterruptedException e) { -+ // ignore -+ } -+- -++ -+ timeout++; -+ } -+- -++ -+ // if we still don't have a response just cancel the request -+ if (!requestor.getResponse()) { -+ if (req != null) -+ req.cancel(); -+ } -+- -++ -+ if (requestor.getResult() == null) -+ return false; -+- -++ -+ SIRetrievable[] rets = requestor.getResult(); -+ for (int i = 0; i < rets.length; i++) { -+ if (rets[i].equals(element)) -+ return true; -+ } -+- -++ -+ return false; -+ } -+- -++ -+ SIElement element; -+ } -+diff --git a/src/libbluray/bdj/java/javax/tv/service/navigation/ServiceTypeFilter.java b/src/libbluray/bdj/java/javax/tv/service/navigation/ServiceTypeFilter.java -+index 0333302..250821e 100644 -+--- a/src/libbluray/bdj/java/javax/tv/service/navigation/ServiceTypeFilter.java -++++ b/src/libbluray/bdj/java/javax/tv/service/navigation/ServiceTypeFilter.java -+@@ -24,6 +24,8 @@ import javax.tv.service.ServiceType; -+ public final class ServiceTypeFilter extends ServiceFilter { -+ public ServiceTypeFilter(ServiceType type) -+ { -++ if (type == null) -++ throw new NullPointerException(); -+ this.type = type; -+ } -+ -+diff --git a/src/libbluray/bdj/java/javax/tv/service/navigation/StreamType.java b/src/libbluray/bdj/java/javax/tv/service/navigation/StreamType.java -+index 5824b44..26dc166 100644 -+--- a/src/libbluray/bdj/java/javax/tv/service/navigation/StreamType.java -++++ b/src/libbluray/bdj/java/javax/tv/service/navigation/StreamType.java -+@@ -22,6 +22,8 @@ package javax.tv.service.navigation; -+ public class StreamType { -+ protected StreamType(String name) -+ { -++ if (name == null) -++ throw new NullPointerException(); -+ this.name = name; -+ } -+ -+diff --git a/src/libbluray/bdj/java/javax/tv/service/selection/ServiceContextFactoryImpl.java b/src/libbluray/bdj/java/javax/tv/service/selection/ServiceContextFactoryImpl.java -+index e1e8dea..2940db4 100644 -+--- a/src/libbluray/bdj/java/javax/tv/service/selection/ServiceContextFactoryImpl.java -++++ b/src/libbluray/bdj/java/javax/tv/service/selection/ServiceContextFactoryImpl.java -+@@ -33,12 +33,14 @@ public class ServiceContextFactoryImpl extends ServiceContextFactory { -+ synchronized (ServiceContextFactoryImpl.class) { -+ if (instance == null) -+ instance = new ServiceContextFactoryImpl(); -++ return instance; -+ } -+- return instance; -+ } -+ -+ public static void shutdown() { -+- instance = null; -++ synchronized (ServiceContextFactoryImpl.class) { -++ instance = null; -++ } -+ } -+ -+ public ServiceContext createServiceContext() -+@@ -60,10 +62,19 @@ public class ServiceContextFactoryImpl extends ServiceContextFactory { -+ } -+ -+ public ServiceContext[] getServiceContexts() { -+- SecurityManager sec = System.getSecurityManager(); -+- if (sec != null) -+- sec.checkPermission(new ServiceContextPermission("access", "own")); -+- return serviceContexts; -++ try { -++ SecurityManager sec = System.getSecurityManager(); -++ if (sec != null) -++ sec.checkPermission(new ServiceContextPermission("access", "own")); -++ -++ ServiceContext[] r = new ServiceContext[1]; -++ r[0] = serviceContexts[0]; -++ return r; -++ -++ } catch (Exception e) { -++ } -++ -++ return new ServiceContext[0]; -+ } -+ -+ private ServiceContext[] serviceContexts; -+diff --git a/src/libbluray/bdj/java/org/bluray/bdplus/Status.java b/src/libbluray/bdj/java/org/bluray/bdplus/Status.java -+index 3f5fcf6..b897b3e 100644 -+--- a/src/libbluray/bdj/java/org/bluray/bdplus/Status.java -++++ b/src/libbluray/bdj/java/org/bluray/bdplus/Status.java -+@@ -28,8 +28,8 @@ public class Status { -+ synchronized (Status.class) { -+ if (instance == null) -+ instance = new Status(); -++ return instance; -+ } -+- return instance; -+ } -+ -+ public static void shutdown() { -+diff --git a/src/libbluray/bdj/java/org/bluray/net/BDLocator.java b/src/libbluray/bdj/java/org/bluray/net/BDLocator.java -+index 6b747cc..a0b593b 100644 -+--- a/src/libbluray/bdj/java/org/bluray/net/BDLocator.java -++++ b/src/libbluray/bdj/java/org/bluray/net/BDLocator.java -+@@ -29,11 +29,11 @@ public class BDLocator extends Locator { -+ super(url); -+ try { -+ -+- if (!url.startsWith("bd://")) -+- throw new InvalidLocatorException(); -+- String str = url.substring(5); -+- if (!parseJar(str) && !parseSound(str) && !parsePlaylist(str)) -+- throw new InvalidLocatorException(); -++ if (!url.startsWith("bd://")) -++ throw new InvalidLocatorException(); -++ String str = url.substring(5); -++ if (!parseJar(str) && !parseSound(str) && !parsePlaylist(str)) -++ throw new InvalidLocatorException(); -+ -+ } catch (InvalidLocatorException e) { -+ System.err.println("Invalid locator: " + url); -+diff --git a/src/libbluray/bdj/java/org/bluray/storage/StorageManager.java b/src/libbluray/bdj/java/org/bluray/storage/StorageManager.java -+index 961c8ec..5ea1c57 100644 -+--- a/src/libbluray/bdj/java/org/bluray/storage/StorageManager.java -++++ b/src/libbluray/bdj/java/org/bluray/storage/StorageManager.java -+@@ -24,8 +24,8 @@ public class StorageManager { -+ synchronized (StorageManager.class) { -+ if (instance == null) -+ instance = new StorageManager(); -++ return instance; -+ } -+- return instance; -+ } -+ -+ protected StorageManager() { -+diff --git a/src/libbluray/bdj/java/org/bluray/ti/selection/TitleContextImpl.java b/src/libbluray/bdj/java/org/bluray/ti/selection/TitleContextImpl.java -+index 0109d2b..48d70be 100644 -+--- a/src/libbluray/bdj/java/org/bluray/ti/selection/TitleContextImpl.java -++++ b/src/libbluray/bdj/java/org/bluray/ti/selection/TitleContextImpl.java -+@@ -38,9 +38,11 @@ import javax.tv.service.selection.ServiceContextPermission; -+ -+ import org.bluray.ti.Title; -+ import org.bluray.ti.TitleImpl; -++ -+ import org.videolan.BDJLoader; -+ import org.videolan.BDJLoaderCallback; -+ import org.videolan.BDJListeners; -++import org.videolan.Logger; -+ import org.videolan.media.content.PlayerManager; -+ -+ public class TitleContextImpl implements TitleContext { -+@@ -71,19 +73,30 @@ public class TitleContextImpl implements TitleContext { -+ } -+ -+ public void start(Title title, boolean restart) throws SecurityException { -++ logger.info("start(" + title.getName() + ", restart=" + restart + ")"); -++ -+ SecurityManager sm = System.getSecurityManager(); -+ if (sm != null) { -+ sm.checkPermission(new SelectPermission(title.getLocator(), "own")); -+ } -+- -+- if (state == STATE_DESTROYED) -++ if (state == STATE_DESTROYED) { -++ logger.error("start() failed: Title Context already destroyed"); -+ throw new IllegalStateException(); -++ } -++ -++ if (!restart && (this.title == null || !title.equals(this.title))) { -++ /* force restarting of service bound Xlets when title changes */ -++ logger.info("start(): title changed, force restart"); -++ restart = true; -++ } -++ -+ TitleStartAction action = new TitleStartAction(this, (TitleImpl)title); -+ if (!BDJLoader.load((TitleImpl)title, restart, action)) -+ action.loaderDone(false); -+ } -+ -+ public void select(Service service) throws SecurityException { -++ logger.info("select(" + service.getName() + ")"); -+ start((Title)service, true); -+ } -+ -+@@ -96,6 +109,8 @@ public class TitleContextImpl implements TitleContext { -+ } -+ -+ public void stop() throws SecurityException { -++ logger.info("stop()"); -++ -+ SecurityManager sm = System.getSecurityManager(); -+ if (sm != null) { -+ sm.checkPermission(new ServiceContextPermission("stop", "own")); -+@@ -187,4 +202,6 @@ public class TitleContextImpl implements TitleContext { -+ private BDJListeners listeners = new BDJListeners(); -+ private TitleImpl title = null; -+ private int state = STATE_STOPPED; -++ -++ private static final Logger logger = Logger.getLogger(TitleContextImpl.class.getName()); -+ } -+diff --git a/src/libbluray/bdj/java/org/dvb/event/EventManager.java b/src/libbluray/bdj/java/org/dvb/event/EventManager.java -+index 2bf2ea4..844b72d 100644 -+--- a/src/libbluray/bdj/java/org/dvb/event/EventManager.java -++++ b/src/libbluray/bdj/java/org/dvb/event/EventManager.java -+@@ -40,8 +40,8 @@ public class EventManager implements ResourceServer { -+ synchronized (EventManager.class) { -+ if (instance == null) -+ instance = new EventManager(); -++ return instance; -+ } -+- return instance; -+ } -+ -+ public static void shutdown() { -+@@ -254,7 +254,7 @@ public class EventManager implements ResourceServer { -+ return false; -+ } -+ -+- private class UserEventItem { -++ private static class UserEventItem { -+ public UserEventItem(BDJXletContext context, UserEventListener listener, -+ ResourceClient client, UserEventRepository userEvents) { -+ this.context = context; -+@@ -272,7 +272,7 @@ public class EventManager implements ResourceServer { -+ public UserEventRepository userEvents; -+ } -+ -+- private class UserEventAction extends BDJAction { -++ private static class UserEventAction extends BDJAction { -+ public UserEventAction(UserEventItem item, UserEvent event) { -+ this.listener = item.listener; -+ this.event = event; -+diff --git a/src/libbluray/bdj/java/org/dvb/io/persistent/FileAttributes.java b/src/libbluray/bdj/java/org/dvb/io/persistent/FileAttributes.java -+index 4c941ff..65c3d29 100644 -+--- a/src/libbluray/bdj/java/org/dvb/io/persistent/FileAttributes.java -++++ b/src/libbluray/bdj/java/org/dvb/io/persistent/FileAttributes.java -+@@ -78,9 +78,9 @@ public class FileAttributes { -+ { -+ boolean r = f.canRead(); -+ boolean w = f.canWrite(); -+- -++ -+ FileAccessPermissions permissions = new FileAccessPermissions(r, w, r, w, r, w); -+- -++ -+ return new FileAttributes(null, permissions, PRIORITY_LOW); -+ } -+ -+diff --git a/src/libbluray/bdj/java/org/dvb/user/UserPreferenceManager.java b/src/libbluray/bdj/java/org/dvb/user/UserPreferenceManager.java -+index 239c966..af86b4e 100644 -+--- a/src/libbluray/bdj/java/org/dvb/user/UserPreferenceManager.java -++++ b/src/libbluray/bdj/java/org/dvb/user/UserPreferenceManager.java -+@@ -31,8 +31,8 @@ public class UserPreferenceManager { -+ synchronized (UserPreferenceManager.class) { -+ if (instance == null) -+ instance = new UserPreferenceManager(); -++ return instance; -+ } -+- return instance; -+ } -+ -+ public void read(Preference p) { -+diff --git a/src/libbluray/bdj/java/org/havi/ui/HScene.java b/src/libbluray/bdj/java/org/havi/ui/HScene.java -+index 7937d32..926781a 100644 -+--- a/src/libbluray/bdj/java/org/havi/ui/HScene.java -++++ b/src/libbluray/bdj/java/org/havi/ui/HScene.java -+@@ -239,8 +239,10 @@ public class HScene extends Container implements HComponentOrdering { -+ } -+ -+ public synchronized void dispose() { -+- if (null != BDJXletContext.getCurrentContext()) -+- HSceneFactory.getInstance().dispose(this); -++ HSceneFactory sf = HSceneFactory.getInstance(); -++ if (sf != null) { -++ sf.dispose(this); -++ } -+ } -+ -+ protected void disposeImpl() -+diff --git a/src/libbluray/bdj/java/org/videolan/BDJAppProxy.java b/src/libbluray/bdj/java/org/videolan/BDJAppProxy.java -+index 135c000..72ba458 100644 -+--- a/src/libbluray/bdj/java/org/videolan/BDJAppProxy.java -++++ b/src/libbluray/bdj/java/org/videolan/BDJAppProxy.java -+@@ -384,8 +384,8 @@ class BDJAppProxy implements DVBJProxy, Runnable { -+ } catch (InterruptedException e) { -+ } -+ } -++ return done; -+ } -+- return done; -+ } -+ -+ public void release() { -+diff --git a/src/libbluray/bdj/java/org/videolan/BDJAppsDatabase.java b/src/libbluray/bdj/java/org/videolan/BDJAppsDatabase.java -+index 13c088f..ca39f12 100644 -+--- a/src/libbluray/bdj/java/org/videolan/BDJAppsDatabase.java -++++ b/src/libbluray/bdj/java/org/videolan/BDJAppsDatabase.java -+@@ -35,8 +35,8 @@ public class BDJAppsDatabase extends AppsDatabase { -+ synchronized (BDJAppsDatabase.class) { -+ if (instance == null) -+ instance = new BDJAppsDatabase(); -++ return instance; -+ } -+- return instance; -+ } -+ -+ public int size() { -+@@ -106,5 +106,5 @@ public class BDJAppsDatabase extends AppsDatabase { -+ private BDJAppProxy[] appProxys = null; -+ private AppEntry[] appTable = null; -+ -+- protected static BDJAppsDatabase instance = null; -++ private static BDJAppsDatabase instance = null; -+ } -+diff --git a/src/libbluray/bdj/java/org/videolan/BDJClassFileTransformer.java b/src/libbluray/bdj/java/org/videolan/BDJClassFileTransformer.java -+new file mode 100644 -+index 0000000..988e76e -+--- /dev/null -++++ b/src/libbluray/bdj/java/org/videolan/BDJClassFileTransformer.java -+@@ -0,0 +1,91 @@ -++/* -++ * This file is part of libbluray -++ * Copyright (C) 2015 Petri Hintukainen <phintuka@users.sourceforge.net> -++ * -++ * This library is free software; you can redistribute it and/or -++ * modify it under the terms of the GNU Lesser General Public -++ * License as published by the Free Software Foundation; either -++ * version 2.1 of the License, or (at your option) any later version. -++ * -++ * This library is distributed in the hope that it will be useful, -++ * but WITHOUT ANY WARRANTY; without even the implied warranty of -++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -++ * Lesser General Public License for more details. -++ * -++ * You should have received a copy of the GNU Lesser General Public -++ * License along with this library. If not, see -++ * <http://www.gnu.org/licenses/>. -++ */ -++ -++package org.videolan; -++ -++/** -++ * This is a class which is called by BDJClassLoader -++ * when ClassFormatError is thrown inside defineClass(). -++ * -++ * Some discs have invalid debug info in class files (broken by -++ * malfunctioning obfuscater ?). -++ * We strip debug info from the class and try to load it again. -++ * -++ * Penguins of MAdagascar: -++ * java.lang.ClassFormatError: Invalid index 0 in LocalVariableTable' -++ * in class file com/tcs/blr/bluray/pal/fox/controller/d -++ */ -++ -++import org.objectweb.asm.ClassReader; -++import org.objectweb.asm.ClassWriter; -++import org.objectweb.asm.ClassVisitor; -++import org.objectweb.asm.MethodVisitor; -++import org.objectweb.asm.Opcodes; -++import org.objectweb.asm.Attribute; -++ -++class BDJClassFileTransformer -++{ -++ public byte[] transform(byte[] b, int off, int len) -++ throws ClassFormatError -++ { -++ logger.info("Trying to transform broken class file (" + len + " bytes)"); -++ -++ byte[] r = new byte[len]; -++ for (int i = 0; i < len; i++) -++ r[i] = b[i+off]; -++ -++ try { -++ ClassReader cr = new ClassReader(r); -++ ClassWriter cw = new ClassWriter(cr, 0/*ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS*/); -++ ClassVisitor cv = new MyClassVisitor(cw); -++ cr.accept(cv, ClassReader.SKIP_DEBUG); -++ return cw.toByteArray(); -++ } catch (Exception e) { -++ logger.error("Failed transforming class: " + e); -++ } -++ -++ return r; -++ } -++ -++ public class MyClassVisitor extends ClassVisitor { -++ public MyClassVisitor(ClassVisitor cv) { -++ super(Opcodes.ASM4, cv); -++ } -++ -++ public MethodVisitor visitMethod(int access, String name, String desc, -++ String signature, String[] exceptions) { -++ MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); -++ //System.err.println("visit method: " + name); -++ return new MyMethodVisitor(mv); -++ } -++ } -++ -++ public class MyMethodVisitor extends MethodVisitor { -++ public MyMethodVisitor(MethodVisitor mv) { -++ super(Opcodes.ASM4, mv); -++ } -++ -++ public void visitAttribute(Attribute attr) { -++ //System.err.println(" attribute: " + attr.type); -++ super.visitAttribute(attr); -++ } -++ } -++ -++ private static final Logger logger = Logger.getLogger(BDJClassFileTransformer.class.getName()); -++} -+diff --git a/src/libbluray/bdj/java/org/videolan/BDJClassLoader.java b/src/libbluray/bdj/java/org/videolan/BDJClassLoader.java -+index 733c3e5..2eb3844 100644 -+--- a/src/libbluray/bdj/java/org/videolan/BDJClassLoader.java -++++ b/src/libbluray/bdj/java/org/videolan/BDJClassLoader.java -+@@ -21,6 +21,7 @@ package org.videolan; -+ -+ import java.net.MalformedURLException; -+ -++import java.io.ByteArrayOutputStream; -+ import java.io.File; -+ import java.io.InputStream; -+ import java.io.IOException; -+@@ -126,7 +127,87 @@ public class BDJClassLoader extends URLClassLoader { -+ } -+ return c; -+ } -+- return super.loadClass(name); -++ -++ try { -++ return super.loadClass(name); -++ } catch (ClassNotFoundException e0) { -++ logger.error("ClassNotFoundException: " + name); -++ throw e0; -++ } catch (Error err) { -++ logger.error("FATAL: " + err); -++ throw err; -++ } -++ } -++ -++ private byte[] loadClassCode(String name) throws ClassNotFoundException { -++ String path = name.replace('.', '/').concat(".class"); -++ -++ URL res = super.findResource(path); -++ if (res == null) { -++ logger.error("loadClassCode(): resource for class " + name + "not found"); -++ throw new ClassNotFoundException(name); -++ } -++ -++ InputStream is = null; -++ ByteArrayOutputStream os = null; -++ try { -++ is = res.openStream(); -++ os = new ByteArrayOutputStream(); -++ byte[] buffer = new byte[0xffff]; -++ while (true) { -++ int r = is.read(buffer); -++ if (r == -1) break; -++ os.write(buffer, 0, r); -++ } -++ -++ return os.toByteArray(); -++ -++ } catch (Exception e) { -++ logger.error("loadClassCode(" + name + ") failed: " + e); -++ throw new ClassNotFoundException(name); -++ -++ } finally { -++ try { -++ if (is != null) -++ is.close(); -++ } catch (IOException ioe) { -++ } -++ try { -++ if (os != null) -++ os.close(); -++ } catch (IOException ioe) { -++ } -++ } -++ } -++ -++ protected Class findClass(String name) throws ClassNotFoundException { -++ try { -++ return super.findClass(name); -++ -++ } catch (ClassFormatError ce) { -++ -++ /* try to "fix" broken class file */ -++ /* if we got ClassFormatError, package was already created. */ -++ byte[] b = loadClassCode(name); -++ if (b == null) { -++ logger.error("loadClassCode(" + name + ") failed"); -++ /* this usually kills Xlet ... */ -++ throw ce; -++ } -++ try { -++ b = new BDJClassFileTransformer().transform(b, 0, b.length); -++ return defineClass(b, 0, b.length); -++ } catch (ThreadDeath td) { -++ throw td; -++ } catch (Throwable t) { -++ logger.error("Class rewriting failed: " + t); -++ throw new ClassNotFoundException(name); -++ } -++ -++ } catch (Error er) { -++ logger.error("Unexpected error: " + er + " " + Logger.dumpStack(er)); -++ throw er; -++ } -+ } -+ -+ public URL getResource(String name) { -+@@ -157,4 +238,6 @@ public class BDJClassLoader extends URLClassLoader { -+ } -+ -+ private String xletClass; -++ -++ private static final Logger logger = Logger.getLogger(BDJClassLoader.class.getName()); -+ } -+diff --git a/src/libbluray/bdj/java/org/videolan/BDJListeners.java b/src/libbluray/bdj/java/org/videolan/BDJListeners.java -+index 77acf4d..ba3a9c5 100644 -+--- a/src/libbluray/bdj/java/org/videolan/BDJListeners.java -++++ b/src/libbluray/bdj/java/org/videolan/BDJListeners.java -+@@ -56,6 +56,8 @@ import org.dvb.media.SubtitleListener; -+ import org.dvb.media.SubtitleNotAvailableEvent; -+ import org.dvb.media.SubtitleNotSelectedEvent; -+ import org.dvb.media.SubtitleSelectedEvent; -++import org.dvb.media.VideoFormatListener; -++import org.dvb.media.VideoFormatEvent; -+ -+ public class BDJListeners { -+ private LinkedList listeners = new LinkedList(); -+@@ -220,6 +222,9 @@ public class BDJListeners { -+ event instanceof SubtitleNotSelectedEvent || event instanceof SubtitleSelectedEvent) { -+ ((SubtitleListener)listener).subtitleStatusChanged((EventObject)event); -+ -++ } else if (event instanceof VideoFormatEvent) { -++ ((VideoFormatListener)listener).receiveVideoFormatEvent((VideoFormatEvent)event); -++ -+ } else if (event instanceof PSR102Status) { -+ ((StatusListener)listener).receive(((PSR102Status)event).value); -+ -+diff --git a/src/libbluray/bdj/java/org/videolan/BDJLoader.java b/src/libbluray/bdj/java/org/videolan/BDJLoader.java -+index 22bd37a..b2bcff3 100644 -+--- a/src/libbluray/bdj/java/org/videolan/BDJLoader.java -++++ b/src/libbluray/bdj/java/org/videolan/BDJLoader.java -+@@ -44,8 +44,60 @@ import org.videolan.media.content.PlayerManager; -+ -+ public class BDJLoader { -+ -++ private static class FontCacheAction extends BDJAction { -++ public FontCacheAction(InputStream is) { -++ this.fontPath = null; -++ this.is = is; -++ } -++ public FontCacheAction(String fontPath) { -++ this.fontPath = fontPath; -++ this.is = null; -++ } -++ -++ protected void doAction() { -++ try { -++ if (this.is != null) { -++ this.cacheFile = addFontImpl(is); -++ } else { -++ this.cacheFile = addFontImpl(fontPath); -++ } -++ } catch (RuntimeException e) { -++ this.exception = e; -++ } -++ } -++ -++ public File execute() { -++ BDJActionManager.getInstance().putCommand(this); -++ waitEnd(); -++ if (exception != null) { -++ throw exception; -++ } -++ return cacheFile; -++ } -++ -++ private final String fontPath; -++ private final InputStream is; -++ private File cacheFile = null; -++ private RuntimeException exception = null; -++ } -++ -+ /* called by org.dvb.ui.FontFactory */ -+ public static File addFont(InputStream is) { -++ if (BDJXletContext.getCurrentContext() == null) -++ return addFontImpl(is); -++ /* dispatch cache request to privileged thread */ -++ return new FontCacheAction(is).execute(); -++ } -++ -++ /* called by org.dvb.ui.FontFactory */ -++ public static File addFont(String fontFile) { -++ if (BDJXletContext.getCurrentContext() == null) -++ return addFontImpl(fontFile); -++ /* dispatch cache request to privileged thread */ -++ return new FontCacheAction(fontFile).execute(); -++ } -++ -++ private static File addFontImpl(InputStream is) { -+ VFSCache localCache = vfsCache; -+ if (localCache != null) { -+ return localCache.addFont(is); -+@@ -53,8 +105,7 @@ public class BDJLoader { -+ return null; -+ } -+ -+- /* called by org.dvb.ui.FontFactory */ -+- public static File addFont(String fontFile) { -++ private static File addFontImpl(String fontFile) { -+ VFSCache localCache = vfsCache; -+ if (localCache != null) { -+ return localCache.addFont(fontFile); -+@@ -134,11 +185,6 @@ public class BDJLoader { -+ throw new InvalidObjectException("bdjo not loaded"); -+ AppEntry[] appTable = bdjo.getAppTable(); -+ -+- // initialize AppCaches -+- if (vfsCache != null) { -+- vfsCache.add(bdjo.getAppCaches()); -+- } -+- -+ // reuse appProxys -+ BDJAppProxy[] proxys = new BDJAppProxy[appTable.length]; -+ AppsDatabase db = AppsDatabase.getAppsDatabase(); -+@@ -147,6 +193,15 @@ public class BDJLoader { -+ AppID id = (AppID)ids.nextElement(); -+ BDJAppProxy proxy = (BDJAppProxy)db.getAppProxy(id); -+ AppEntry entry = (AppEntry)db.getAppAttributes(id); -++ if (proxy == null) { -++ logger.error("AppsDatabase corrupted!"); -++ continue; -++ } -++ if (entry == null) { -++ logger.error("AppsDatabase corrupted!"); -++ proxy.release(); -++ continue; -++ } -+ for (int i = 0; i < appTable.length; i++) { -+ if (id.equals(appTable[i].getIdentifier()) && -+ entry.getInitialClass().equals(appTable[i].getInitialClass())) { -+@@ -155,7 +210,6 @@ public class BDJLoader { -+ proxy.stop(true); -+ } else { -+ logger.info("Keeping xlet " + appTable[i].getInitialClass()); -+- proxy.getXletContext().update(appTable[i], bdjo.getAppCaches()); -+ proxys[i] = proxy; -+ proxy = null; -+ } -+@@ -180,6 +234,11 @@ public class BDJLoader { -+ Libbluray.setUOMask(terminfo.getMenuCallMask(), terminfo.getTitleSearchMask()); -+ Libbluray.setKeyInterest(bdjo.getKeyInterestTable()); -+ -++ // initialize AppCaches -++ if (vfsCache != null) { -++ vfsCache.add(bdjo.getAppCaches()); -++ } -++ -+ // initialize appProxys -+ for (int i = 0; i < appTable.length; i++) { -+ if (proxys[i] == null) { -+@@ -196,6 +255,7 @@ public class BDJLoader { -+ } -+ logger.info("Loaded class: " + appTable[i].getInitialClass() + p + " from " + appTable[i].getBasePath() + ".jar"); -+ } else { -++ proxys[i].getXletContext().update(appTable[i], bdjo.getAppCaches()); -+ logger.info("Reused class: " + appTable[i].getInitialClass() + " from " + appTable[i].getBasePath() + ".jar"); -+ } -+ } -+@@ -206,6 +266,19 @@ public class BDJLoader { -+ // notify AppsDatabase -+ ((BDJAppsDatabase)BDJAppsDatabase.getAppsDatabase()).newDatabase(bdjo, proxys); -+ -++ // auto start playlist -++ try { -++ PlayListTable plt = bdjo.getAccessiblePlaylists(); -++ if ((plt != null) && (plt.isAutostartFirst())) { -++ logger.info("Auto-starting playlist"); -++ String[] pl = plt.getPlayLists(); -++ if (pl.length > 0) -++ Manager.createPlayer(new MediaLocator(new BDLocator("bd://PLAYLIST:" + pl[0]))).start(); -++ } -++ } catch (Exception e) { -++ logger.error("loadN(): autoplaylist failed: " + e + "\n" + Logger.dumpStack(e)); -++ } -++ -+ // now run all the xlets -+ for (int i = 0; i < appTable.length; i++) { -+ int code = appTable[i].getControlCode(); -+@@ -222,15 +295,6 @@ public class BDJLoader { -+ -+ logger.info("Finished initializing and starting xlets."); -+ -+- // auto start playlist -+- PlayListTable plt = bdjo.getAccessiblePlaylists(); -+- if ((plt != null) && (plt.isAutostartFirst())) { -+- logger.info("Auto-starting playlist"); -+- String[] pl = plt.getPlayLists(); -+- if (pl.length > 0) -+- Manager.createPlayer(new MediaLocator(new BDLocator("bd://PLAYLIST:" + pl[0]))).start(); -+- } -+- -+ return true; -+ -+ } catch (Throwable e) { -+diff --git a/src/libbluray/bdj/java/org/videolan/BDJSecurityManager.java b/src/libbluray/bdj/java/org/videolan/BDJSecurityManager.java -+index 38f8ac5..8a337ee 100644 -+--- a/src/libbluray/bdj/java/org/videolan/BDJSecurityManager.java -++++ b/src/libbluray/bdj/java/org/videolan/BDJSecurityManager.java -+@@ -76,6 +76,14 @@ final class BDJSecurityManager extends SecurityManager { -+ } -+ deny(perm); -+ } -++ -++ // work around bug in openjdk 7 / 8 -++ // sun.awt.AWTAutoShutdown.notifyThreadBusy is missing doPrivileged() -++ // (fixed in jdk9 / http://hg.openjdk.java.net/jdk9/client/jdk/rev/5b613a3c04be ) -++ if (classDepth("sun.awt.AWTAutoShutdown") > 0) { -++ return; -++ } -++ -+ if (perm.implies(new RuntimePermission("modifyThreadGroup"))) { -+ /* do check here (no need to log failures) */ -+ super.checkPermission(perm); -+@@ -119,6 +127,10 @@ final class BDJSecurityManager extends SecurityManager { -+ return; -+ } -+ } -++ if (perm.getActions().contains("write")) { -++ /* write permissions are handled in checkWrite() */ -++ deny(perm); -++ } -+ } -+ -+ /* Networking */ -+@@ -180,6 +192,10 @@ final class BDJSecurityManager extends SecurityManager { -+ throw new SecurityException("exit denied"); -+ } -+ -++ public void checkSystemClipboardAccess() { -++ throw new SecurityException("clipboard access denied"); -++ } -++ -+ /* -+ * file read access -+ */ -+diff --git a/src/libbluray/bdj/java/org/videolan/BDJThreadGroup.java b/src/libbluray/bdj/java/org/videolan/BDJThreadGroup.java -+index f4bc1dc..4943a7e 100644 -+--- a/src/libbluray/bdj/java/org/videolan/BDJThreadGroup.java -++++ b/src/libbluray/bdj/java/org/videolan/BDJThreadGroup.java -+@@ -20,9 +20,9 @@ -+ -+ package org.videolan; -+ -+-public class BDJThreadGroup extends ThreadGroup { -++class BDJThreadGroup extends ThreadGroup { -+ -+- public BDJThreadGroup(String name, BDJXletContext context) { -++ protected BDJThreadGroup(String name, BDJXletContext context) { -+ super(name); -+ this.context = context; -+ } -+@@ -45,15 +45,11 @@ public class BDJThreadGroup extends ThreadGroup { -+ } -+ } -+ -+- public BDJXletContext getContext() { -++ protected BDJXletContext getContext() { -+ return context; -+ } -+ -+- public void setContext(BDJXletContext context) { -+- this.context = context; -+- } -+- -+- public boolean waitForShutdown(int timeout, int maxThreads) { -++ protected boolean waitForShutdown(int timeout, int maxThreads) { -+ -+ if (parentOf(Thread.currentThread().getThreadGroup()) && maxThreads < 1) { -+ logger.error("Current Thread is contained within ThreadGroup to be disposed."); -+@@ -94,8 +90,6 @@ public class BDJThreadGroup extends ThreadGroup { -+ } catch (IllegalThreadStateException e) { -+ logger.error("ThreadGroup destroy failed: " + e); -+ } -+- -+- context = null; -+ } -+ -+ public void dumpThreads() { -+@@ -115,6 +109,6 @@ public class BDJThreadGroup extends ThreadGroup { -+ } -+ } -+ -+- private BDJXletContext context; -++ private final BDJXletContext context; -+ private static final Logger logger = Logger.getLogger(BDJThreadGroup.class.getName()); -+ } -+diff --git a/src/libbluray/bdj/java/org/videolan/BDJUtil.java b/src/libbluray/bdj/java/org/videolan/BDJUtil.java -+index 507c2e7..cc17992 100644 -+--- a/src/libbluray/bdj/java/org/videolan/BDJUtil.java -++++ b/src/libbluray/bdj/java/org/videolan/BDJUtil.java -+@@ -25,20 +25,31 @@ public class BDJUtil { -+ /** -+ * Make a five digit zero padded string based on an integer -+ * Ex. integer 1 -> string "00001" -+- * -++ * -+ * @param id -+ * @return -+ */ -+- public static String makeFiveDigitStr(int id) -++ public static String makeFiveDigitStr(int id) -+ { -++ if (id < 0 || id > 99999) { -++ System.err.println("Invalid ID: " + id); -++ throw new IllegalArgumentException("Invalid ID " + id); -++ } -++ String s = "" + id; -++ while (s.length() < 5) { -++ s = "0" + s; -++ } -++ return s; -++ /* -+ DecimalFormat fmt = new DecimalFormat(); -+ fmt.setMaximumIntegerDigits(5); -+ fmt.setMinimumIntegerDigits(5); -+ fmt.setGroupingUsed(false); -+- -++ -+ return fmt.format(id); -++ */ -+ } -+- -++ -+ /** -+ * Make a path based on the disc root to an absolute path based on the filesystem of the computer -+ * Ex. /BDMV/JAR/00000.jar -> /bluray/disc/mount/point/BDMV/JAR/00000.jar -+@@ -47,6 +58,11 @@ public class BDJUtil { -+ */ -+ public static String discRootToFilesystem(String path) -+ { -+- return System.getProperty("bluray.vfs.root") + path; -++ String vfsRoot = System.getProperty("bluray.vfs.root"); -++ if (vfsRoot == null) { -++ System.err.println("discRootToFilesystem(): disc root not set !"); -++ return path; -++ } -++ return vfsRoot + path; -+ } -+ } -+diff --git a/src/libbluray/bdj/java/org/videolan/BDJXletContext.java b/src/libbluray/bdj/java/org/videolan/BDJXletContext.java -+index ae5b3a0..8ee818a 100644 -+--- a/src/libbluray/bdj/java/org/videolan/BDJXletContext.java -++++ b/src/libbluray/bdj/java/org/videolan/BDJXletContext.java -+@@ -70,7 +70,12 @@ public class BDJXletContext implements javax.tv.xlet.XletContext, javax.microedi -+ try { -+ int homeJarID = Integer.parseInt(home); -+ long time = System.currentTimeMillis(); -+- homeMountPoint = MountManager.mount(homeJarID, false) + java.io.File.separator; -++ homeMountPoint = MountManager.mount(homeJarID, false); -++ if (homeMountPoint == null) { -++ logger.error("Failed mounting " + home + ".jar"); -++ } else { -++ homeMountPoint = homeMountPoint + java.io.File.separator; -++ } -+ time = System.currentTimeMillis() - time; -+ logger.info("Mounted Xlet home directory from " + home + ".jar " + -+ "to " + homeMountPoint + "(" + time + "ms)"); -+@@ -80,6 +85,8 @@ public class BDJXletContext implements javax.tv.xlet.XletContext, javax.microedi -+ } -+ -+ public String getXletHome() { -++ if (homeMountPoint == null) -++ logger.error("Home directory not mounted!"); -+ return homeMountPoint; -+ } -+ -+@@ -102,6 +109,8 @@ public class BDJXletContext implements javax.tv.xlet.XletContext, javax.microedi -+ return Integer.toHexString(appid.getAID()); -+ else if (key.equals("org.dvb.application.appid")) -+ return appid; -++ -++ logger.error("unhandled getXletProperty(" + key + ")"); -+ return null; -+ } -+ -+diff --git a/src/libbluray/bdj/java/org/videolan/IxcRegistryImpl.java b/src/libbluray/bdj/java/org/videolan/IxcRegistryImpl.java -+index a9fe28d..bae986f 100644 -+--- a/src/libbluray/bdj/java/org/videolan/IxcRegistryImpl.java -++++ b/src/libbluray/bdj/java/org/videolan/IxcRegistryImpl.java -+@@ -260,7 +260,7 @@ public class IxcRegistryImpl { -+ return result; -+ } -+ -+- public class RemoteMethod implements Runnable -++ private class RemoteMethod implements Runnable -+ { -+ final BDJXletContext calleeContext; -+ final BDJXletContext callerContext; -+@@ -276,9 +276,11 @@ public class IxcRegistryImpl { -+ callerContext = BDJXletContext.getCurrentContext(); -+ if (callerContext == null) { -+ logger.error("caller context is null"); -++ throw new RemoteException("no caller context"); -+ } -+ if (context == null) { -+ logger.error("callee context is null"); -++ throw new RemoteException("no callee context"); -+ } -+ calleeContext = context; -+ -+@@ -426,6 +428,18 @@ public class IxcRegistryImpl { -+ throw new IllegalArgumentException("xc not current BDJXletContext"); -+ } -+ -++ if ("/7fff7669/4050/Messenger".equals(path)) { -++ /* known discs: -++ - Terminator Salvation -++ */ -++ try { -++ logger.error("Enabling Ixc delay hack for " + path); -++ Thread.sleep(200L); -++ } catch (InterruptedException ie) { -++ ie.printStackTrace(); -++ } -++ } -++ -+ WrappedRemoteObj wrappedObj = null; -+ synchronized (remoteObjects) { -+ if (!remoteObjects.containsKey(path)) { -+@@ -438,7 +452,7 @@ public class IxcRegistryImpl { -+ } -+ Object remoteObj = wrapOrCopy(wrappedObj, wrappedObj.context, (BDJXletContext)xc); -+ -+- Debug("IxcRegistry.lookup(" + path + ") => " + remoteObj); -++ Debug("IxcRegistry.lookup(" + path + ") => OK"); -+ -+ return (Remote)remoteObj; -+ } -+diff --git a/src/libbluray/bdj/java/org/videolan/Libbluray.java b/src/libbluray/bdj/java/org/videolan/Libbluray.java -+index 41af18f..6a97ad7 100644 -+--- a/src/libbluray/bdj/java/org/videolan/Libbluray.java -++++ b/src/libbluray/bdj/java/org/videolan/Libbluray.java -+@@ -24,6 +24,8 @@ import java.awt.BDFontMetrics; -+ import java.awt.BDToolkit; -+ import java.awt.event.KeyEvent; -+ import java.io.File; -++import java.util.HashMap; -++import java.util.Map; -+ import java.util.Vector; -+ -+ import javax.media.PackageManager; -+@@ -50,14 +52,7 @@ public class Libbluray { -+ -+ /* hook system properties: make "user.dir" point to current Xlet home directory */ -+ -+- private static boolean propertiesHooked = false; -+- -+ private static void hookProperties() { -+- if (propertiesHooked) { -+- return; -+- } -+- propertiesHooked = true; -+- -+ java.util.Properties p = new java.util.Properties(System.getProperties()) { -+ public String getProperty(String key) { -+ if (key.equals("user.dir")) { -+@@ -65,6 +60,7 @@ public class Libbluray { -+ if (ctx != null) { -+ return ctx.getXletHome(); -+ } -++ System.err.println("getProperty(user.dir): no context ! " + Logger.dumpStack()); -+ } -+ return super.getProperty(key); -+ } -+@@ -72,6 +68,28 @@ public class Libbluray { -+ System.setProperties(p); -+ } -+ -++ private static boolean initOnce = false; -++ private static void initOnce() { -++ if (initOnce) { -++ return; -++ } -++ initOnce = true; -++ -++ /* hook system properties (provide Xlet-specific user.dir) */ -++ try { -++ hookProperties(); -++ } catch (Throwable t) { -++ System.err.println("hookProperties() failed: " + t); -++ } -++ -++ /* hook sockets (limit network connections) */ -++ try { -++ BDJSocketFactory.init(); -++ } catch (Throwable t) { -++ System.err.println("Hooking socket factory failed: " + t + "\n" + Logger.dumpStack(t)); -++ } -++ } -++ -+ private static String canonicalize(String path, boolean create) { -+ try { -+ File dir = new File(path); -+@@ -89,7 +107,7 @@ public class Libbluray { -+ private static void init(long nativePointer, String discID, String discRoot, -+ String persistentRoot, String budaRoot) { -+ -+- hookProperties(); -++ initOnce(); -+ -+ /* set up directories */ -+ persistentRoot = canonicalize(persistentRoot, true); -+@@ -185,8 +203,6 @@ public class Libbluray { -+ -+ System.setProperty("bluray.network.connected", "YES"); -+ -+- BDJSocketFactory.init(); -+- -+ try { -+ System.setSecurityManager(new BDJSecurityManager(discRoot, persistentRoot, budaRoot)); -+ } catch (Exception ex) { -+@@ -228,6 +244,7 @@ public class Libbluray { -+ } -+ nativePointer = 0; -+ titleInfos = null; -++ bdjoFiles = null; -+ } -+ -+ /* -+@@ -296,6 +313,10 @@ public class Libbluray { -+ * Disc data -+ */ -+ -++ /* cache parsed .bdjo files */ -++ private static Map bdjoFiles = null; -++ private static Object bdjoFilesLock = new Object(); -++ -+ public static byte[] getAacsData(int type) { -+ return getAacsDataN(nativePointer, type); -+ } -+@@ -305,7 +326,23 @@ public class Libbluray { -+ } -+ -+ public static Bdjo getBdjo(String name) { -+- return getBdjoN(nativePointer, name + ".bdjo"); -++ Bdjo bdjo; -++ synchronized (bdjoFilesLock) { -++ if (bdjoFiles == null) { -++ bdjoFiles = new HashMap(); -++ } else { -++ bdjo = (Bdjo)bdjoFiles.get(name); -++ if (bdjo != null) { -++ return bdjo; -++ } -++ } -++ -++ bdjo = getBdjoN(nativePointer, name + ".bdjo"); -++ if (bdjo != null) { -++ bdjoFiles.put(name, bdjo); -++ } -++ return bdjo; -++ } -+ } -+ -+ public static String[] listBdFiles(String path, boolean onlyBdRom) { -+diff --git a/src/libbluray/bdj/java/org/videolan/MountManager.java b/src/libbluray/bdj/java/org/videolan/MountManager.java -+index 83d6870..6f6fd52 100644 -+--- a/src/libbluray/bdj/java/org/videolan/MountManager.java -++++ b/src/libbluray/bdj/java/org/videolan/MountManager.java -+@@ -185,6 +185,7 @@ public class MountManager { -+ new PrivilegedAction() { -+ public Object run() { -+ if (mountPoint.decRefCount() < 1) { -++ logger.error("Removing JAR " + id + " from mount cache"); -+ mountPoints.remove(id); -+ } -+ return null; -+@@ -221,7 +222,7 @@ public class MountManager { -+ if (mountPoint != null) { -+ return mountPoint.getMountPoint(); -+ } else { -+- logger.info("JAR " + jarId + " not mounted"); -++ logger.error("JAR " + jarId + " not mounted"); -+ } -+ return null; -+ } -+@@ -247,6 +248,7 @@ public class MountManager { -+ if (dir != null) { -+ return dir.getAbsolutePath(); -+ } -++ logger.error("getMountPoint(): already unmounted !"); -+ return null; -+ } -+ -+@@ -274,8 +276,8 @@ public class MountManager { -+ return classFiles; -+ } -+ -+- public boolean setClassFiles() { -+- return classFiles == true; -++ public void setClassFiles() { -++ classFiles = true; -+ } -+ -+ private File dir; -+diff --git a/src/libbluray/bdj/java/org/videolan/TitleInfo.java b/src/libbluray/bdj/java/org/videolan/TitleInfo.java -+index 1c1075b..10dc62a 100644 -+--- a/src/libbluray/bdj/java/org/videolan/TitleInfo.java -++++ b/src/libbluray/bdj/java/org/videolan/TitleInfo.java -+@@ -24,7 +24,7 @@ public class TitleInfo { -+ this.objType = objType; -+ this.playbackType = playbackType; -+ if (objType == OBJ_TYPE_BDJ) -+- this.bdjoName = (new java.text.DecimalFormat("00000")).format(idRef); -++ this.bdjoName = (BDJUtil.makeFiveDigitStr(idRef)); -+ else -+ this.hdmvOID = idRef; -+ } -+diff --git a/src/libbluray/bdj/java/org/videolan/VFSCache.java b/src/libbluray/bdj/java/org/videolan/VFSCache.java -+index 2bcfbe9..22fe1f0 100644 -+--- a/src/libbluray/bdj/java/org/videolan/VFSCache.java -++++ b/src/libbluray/bdj/java/org/videolan/VFSCache.java -+@@ -270,16 +270,19 @@ class VFSCache { -+ accessFileSynced(absPath); -+ } -+ -+- protected synchronized void accessFileSynced(String absPath) { -++ private synchronized void accessFileSynced(String absPath) { -+ -+ if (inAccessFile) { -+ /* avoid recursion from SecurityManager checks */ -+ return; -+ } -+ -+- inAccessFile = true; -+- accessFileImp(absPath); -+- inAccessFile = false; -++ try { -++ inAccessFile = true; -++ accessFileImp(absPath); -++ } finally { -++ inAccessFile = false; -++ } -+ } -+ -+ private void accessFileImp(String absPath) { -+@@ -297,7 +300,7 @@ class VFSCache { -+ } -+ -+ /* do not cache .m2ts streams */ -+- if (relPath.startsWith("BDMV" + File.separator + "STREAM" + File.separator)) { -++ if (relPath.startsWith(streamDir)) { -+ return; -+ } -+ -+@@ -352,6 +355,7 @@ class VFSCache { -+ -+ private static final String jarDir = "BDMV" + File.separator + "JAR" + File.separator; -+ private static final String fontDir = "BDMV" + File.separator + "AUXDATA" + File.separator; -++ private static final String streamDir = "BDMV" + File.separator + "STREAM" + File.separator; -+ -+ private static final Logger logger = Logger.getLogger(VFSCache.class.getName()); -+ } -+diff --git a/src/libbluray/bdj/java/org/videolan/media/content/BDHandler.java b/src/libbluray/bdj/java/org/videolan/media/content/BDHandler.java -+index 3d43579..92269f1 100644 -+--- a/src/libbluray/bdj/java/org/videolan/media/content/BDHandler.java -++++ b/src/libbluray/bdj/java/org/videolan/media/content/BDHandler.java -+@@ -67,10 +67,13 @@ public abstract class BDHandler implements Player, ServiceContentHandler { -+ -+ public BDHandler() { -+ ownerContext = BDJXletContext.getCurrentContext(); -+- -+- PlayerAction action = new PlayerAction(this, PlayerAction.ACTION_INIT, null); -+- BDJActionManager.getInstance().putCommand(action); -+- action.waitEnd(); -++ if (ownerContext == null) { -++ doInitAction(); -++ } else { -++ PlayerAction action = new PlayerAction(this, PlayerAction.ACTION_INIT, null); -++ BDJActionManager.getInstance().putCommand(action); -++ action.waitEnd(); -++ } -+ } -+ -+ private void doInitAction() { -+diff --git a/src/libbluray/bdj/java/org/videolan/media/content/PlayerManager.java b/src/libbluray/bdj/java/org/videolan/media/content/PlayerManager.java -+index cc06e84..d45358b 100644 -+--- a/src/libbluray/bdj/java/org/videolan/media/content/PlayerManager.java -++++ b/src/libbluray/bdj/java/org/videolan/media/content/PlayerManager.java -+@@ -19,6 +19,7 @@ -+ package org.videolan.media.content; -+ -+ import java.util.ArrayList; -++import org.videolan.Logger; -+ -+ public class PlayerManager { -+ -+@@ -81,7 +82,7 @@ public class PlayerManager { -+ return; -+ } -+ -+- System.err.println("unknown player type: " + player.getClass().getName()); -++ logger.error("unknown player type: " + player.getClass().getName()); -+ } -+ -+ protected boolean allocateResource(BDHandler player) { -+@@ -91,6 +92,9 @@ public class PlayerManager { -+ } -+ synchronized (playlistPlayerLock) { -+ if (playlistPlayer != null && player != playlistPlayer) { -++ -++ logger.info("allocateResource(): Stopping old playlist player"); -++ -+ playlistPlayer.stop(); -+ playlistPlayer.deallocate(); -+ } -+@@ -108,7 +112,7 @@ public class PlayerManager { -+ return true; -+ } -+ -+- System.err.println("unknown player type: " + player.getClass().getName()); -++ logger.error("allocateResource(): unknown player type: " + player.getClass().getName()); -+ return false; -+ } -+ -+@@ -153,4 +157,6 @@ public class PlayerManager { -+ } -+ } -+ } -++ -++ private static final Logger logger = Logger.getLogger(PlayerManager.class.getName()); -+ } -+diff --git a/src/libbluray/bdj/java/org/videolan/media/content/playlist/BackgroundVideoPresentationControlImpl.java b/src/libbluray/bdj/java/org/videolan/media/content/playlist/BackgroundVideoPresentationControlImpl.java -+index 05ae554..21f6de5 100644 -+--- a/src/libbluray/bdj/java/org/videolan/media/content/playlist/BackgroundVideoPresentationControlImpl.java -++++ b/src/libbluray/bdj/java/org/videolan/media/content/playlist/BackgroundVideoPresentationControlImpl.java -+@@ -53,6 +53,8 @@ public class BackgroundVideoPresentationControlImpl extends VideoControl -+ } -+ -+ public boolean setVideoTransformation(VideoTransformation transform) { -++ if (transform == null) -++ return false; -+ setClipRegion(transform.getClipRegion()); -+ HScreenPoint pos = transform.getVideoPosition(); -+ float[] scales = transform.getScalingFactors(); -+@@ -99,40 +101,40 @@ public class BackgroundVideoPresentationControlImpl extends VideoControl -+ return new AWTVideoSize( -+ new Rectangle(vd.width, vd.height), -+ new Rectangle(sd.width, sd.height)); -+- } -++ } -+ -+- public Dimension getSourceVideoSize() { -+- return getVideoSize(); -+- } -++ public Dimension getSourceVideoSize() { -++ return getVideoSize(); -++ } -+ -+- public boolean setSize(AWTVideoSize size) { -+- setClipRegion(size.getSource()); -+- setVideoArea(getNormalizedRectangle(getScreenSize(), size.getDestination())); -+- return true; -+- } -++ public boolean setSize(AWTVideoSize size) { -++ setClipRegion(size.getSource()); -++ setVideoArea(getNormalizedRectangle(getScreenSize(), size.getDestination())); -++ return true; -++ } -+ -+- public AWTVideoSize checkSize(AWTVideoSize size) { -+- Dimension vd = getInputVideoSize(); -+- Rectangle sr = size.getSource(); -+- if (sr.x < 0) -++ public AWTVideoSize checkSize(AWTVideoSize size) { -++ Dimension vd = getInputVideoSize(); -++ Rectangle sr = size.getSource(); -++ if (sr.x < 0) -++ sr.x = 0; -++ if ((sr.x + sr.width) > vd.width) { -++ sr.width = vd.width - sr.x; -++ if (sr.width <= 0) { -+ sr.x = 0; -+- if ((sr.x + sr.width) > vd.width) { -+- sr.width = vd.width - sr.x; -+- if (sr.width <= 0) { -+- sr.x = 0; -+- sr.width = 0; -+- } -++ sr.width = 0; -+ } -+- if (sr.y < 0) -++ } -++ if (sr.y < 0) -++ sr.y = 0; -++ if ((sr.y + sr.height) > vd.height) { -++ sr.height = vd.height - sr.y; -++ if (sr.height <= 0) { -+ sr.y = 0; -+- if ((sr.y + sr.height) > vd.height) { -+- sr.height = vd.height - sr.y; -+- if (sr.height <= 0) { -+- sr.y = 0; -+- sr.height = 0; -+- } -++ sr.height = 0; -+ } -+- Rectangle dr = size.getDestination(); -+- return new AWTVideoSize(sr, dr); -+ } -++ Rectangle dr = size.getDestination(); -++ return new AWTVideoSize(sr, dr); -++ } -+ } -+diff --git a/src/libbluray/bdj/java/org/videolan/media/content/playlist/Handler.java b/src/libbluray/bdj/java/org/videolan/media/content/playlist/Handler.java -+index 7e52949..8728628 100644 -+--- a/src/libbluray/bdj/java/org/videolan/media/content/playlist/Handler.java -++++ b/src/libbluray/bdj/java/org/videolan/media/content/playlist/Handler.java -+@@ -72,6 +72,7 @@ public class Handler extends BDHandler { -+ synchronized (this) { -+ try { -+ locator = new BDLocator(source.getLocator().toExternalForm()); -++ currentLocator = null; -+ } catch (org.davic.net.InvalidLocatorException e) { -+ throw new IncompatibleSourceException(); -+ } -+@@ -294,7 +295,11 @@ public class Handler extends BDHandler { -+ -+ protected void doEndOfMediaReached(int playlist) { -+ synchronized (this) { -+- if (locator == null || locator.getPlayListId() != playlist) { -++ if (locator == null) { -++ System.err.println("endOfMedia(" + playlist + ") ignored: no current locator"); -++ return; -++ } -++ if (locator.getPlayListId() != playlist) { -+ System.err.println("endOfMedia ignored: playlist does not match (" + playlist + " != " + locator.getPlayListId()); -+ return; -+ } -+@@ -336,6 +341,7 @@ public class Handler extends BDHandler { -+ if (pi == null) -+ throw new InvalidPlayListException(); -+ this.locator = locator; -++ this.currentLocator = null; -+ baseMediaTime = 0; -+ if (state == Prefetched) -+ doPrefetch(); -+diff --git a/src/libbluray/bdj/java/org/videolan/media/content/video/dvb/mpeg/drip/BackgroundVideoPresentationControlImpl.java b/src/libbluray/bdj/java/org/videolan/media/content/video/dvb/mpeg/drip/BackgroundVideoPresentationControlImpl.java -+index 3596def..377aacc 100644 -+--- a/src/libbluray/bdj/java/org/videolan/media/content/video/dvb/mpeg/drip/BackgroundVideoPresentationControlImpl.java -++++ b/src/libbluray/bdj/java/org/videolan/media/content/video/dvb/mpeg/drip/BackgroundVideoPresentationControlImpl.java -+@@ -100,23 +100,23 @@ public class BackgroundVideoPresentationControlImpl extends VideoControl -+ Rectangle sr = size.getSource(); -+ if (sr.x < 0) -+ sr.x = 0; -+- if ((sr.x + sr.width) > vd.width) { -+- sr.width = vd.width - sr.x; -+- if (sr.width <= 0) { -+- sr.x = 0; -+- sr.width = 0; -+- } -++ if ((sr.x + sr.width) > vd.width) { -++ sr.width = vd.width - sr.x; -++ if (sr.width <= 0) { -++ sr.x = 0; -++ sr.width = 0; -+ } -+- if (sr.y < 0) -++ } -++ if (sr.y < 0) -++ sr.y = 0; -++ if ((sr.y + sr.height) > vd.height) { -++ sr.height = vd.height - sr.y; -++ if (sr.height <= 0) { -+ sr.y = 0; -+- if ((sr.y + sr.height) > vd.height) { -+- sr.height = vd.height - sr.y; -+- if (sr.height <= 0) { -+- sr.y = 0; -+- sr.height = 0; -+- } -++ sr.height = 0; -+ } -+- Rectangle dr = size.getDestination(); -+- return new AWTVideoSize(sr, dr); -++ } -++ Rectangle dr = size.getDestination(); -++ return new AWTVideoSize(sr, dr); -+ } -+ } -+diff --git a/src/libbluray/bdj/native/java_awt_BDFontMetrics.c b/src/libbluray/bdj/native/java_awt_BDFontMetrics.c -+index 3bbd3c3..f84a382 100644 -+--- a/src/libbluray/bdj/native/java_awt_BDFontMetrics.c -++++ b/src/libbluray/bdj/native/java_awt_BDFontMetrics.c -+@@ -135,7 +135,10 @@ static char *_win32_resolve_font(const char *family, int style) -+ -+ memset(&lf, 0, sizeof(lf)); -+ lf.lfCharSet = DEFAULT_CHARSET; -+- MultiByteToWideChar(CP_UTF8, 0, family, -1, lf.lfFaceName, sizeof(lf.lfFaceName)); -++ int length = MultiByteToWideChar(CP_UTF8, 0, family, -1, lf.lfFaceName, LF_FACESIZE); -++ if (!length) { -++ return NULL; -++ } -+ -+ hDC = GetDC(NULL); -+ EnumFontFamiliesExW(hDC, &lf, (FONTENUMPROCW)&EnumFontCallbackW, (LPARAM)&data, 0); +diff --git a/src/libbluray/bdnav/clpi_parse.c b/src/libbluray/bdnav/clpi_parse.c -+index 365ec0f..f0826de 100644 ++index 394347e..39bbcef 100644 +--- a/src/libbluray/bdnav/clpi_parse.c ++++ b/src/libbluray/bdnav/clpi_parse.c +@@ -39,6 +39,7 @@ @@ -76902,244 +50932,8 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + + char sig[9]; + char expect[9]; -+@@ -223,7 +225,7 @@ _parse_sequence(BITSTREAM *bits, CLPI_CL *cl) -+ cl->sequence.num_atc_seq = bs_read(bits, 8); -+ -+ CLPI_ATC_SEQ *atc_seq; -+- atc_seq = malloc(cl->sequence.num_atc_seq * sizeof(CLPI_ATC_SEQ)); -++ atc_seq = calloc(cl->sequence.num_atc_seq, sizeof(CLPI_ATC_SEQ)); -+ cl->sequence.atc_seq = atc_seq; -+ for (ii = 0; ii < cl->sequence.num_atc_seq; ii++) { -+ atc_seq[ii].spn_atc_start = bs_read(bits, 32); -+@@ -254,7 +256,7 @@ _parse_program(BITSTREAM *bits, CLPI_PROG_INFO *program) -+ program->num_prog = bs_read(bits, 8); -+ -+ CLPI_PROG *progs; -+- progs = malloc(program->num_prog * sizeof(CLPI_PROG)); -++ progs = calloc(program->num_prog, sizeof(CLPI_PROG)); -+ program->progs = progs; -+ for (ii = 0; ii < program->num_prog; ii++) { -+ progs[ii].spn_program_sequence_start = bs_read(bits, 32); -+@@ -263,7 +265,7 @@ _parse_program(BITSTREAM *bits, CLPI_PROG_INFO *program) -+ progs[ii].num_groups = bs_read(bits, 8); -+ -+ CLPI_PROG_STREAM *ps; -+- ps = malloc(progs[ii].num_streams * sizeof(CLPI_PROG_STREAM)); -++ ps = calloc(progs[ii].num_streams, sizeof(CLPI_PROG_STREAM)); -+ progs[ii].streams = ps; -+ for (jj = 0; jj < progs[ii].num_streams; jj++) { -+ ps[jj].pid = bs_read(bits, 16); -+@@ -335,7 +337,7 @@ _parse_cpi(BITSTREAM *bits, CLPI_CPI *cpi) -+ cpi->num_stream_pid = bs_read(bits, 8); -+ -+ CLPI_EP_MAP_ENTRY *entry; -+- entry = malloc(cpi->num_stream_pid * sizeof(CLPI_EP_MAP_ENTRY)); -++ entry = calloc(cpi->num_stream_pid, sizeof(CLPI_EP_MAP_ENTRY)); -+ cpi->entry = entry; -+ for (ii = 0; ii < cpi->num_stream_pid; ii++) { -+ entry[ii].pid = bs_read(bits, 16); -+@@ -622,12 +624,12 @@ _clean_program(CLPI_PROG_INFO *p) -+ { -+ int ii; -+ -+- for (ii = 0; ii < p->num_prog; ii++) { -+- if (p->progs[ii].streams != NULL) { -++ if (p && p->progs) { -++ for (ii = 0; ii < p->num_prog; ii++) { -+ X_FREE(p->progs[ii].streams); -+ } -++ X_FREE(p->progs); -+ } -+- X_FREE(p->progs); -+ } -+ -+ static void -+@@ -635,15 +637,13 @@ _clean_cpi(CLPI_CPI *cpi) -+ { -+ int ii; -+ -+- for (ii = 0; ii < cpi->num_stream_pid; ii++) { -+- if (cpi->entry[ii].coarse != NULL) { -++ if (cpi && cpi->entry) { -++ for (ii = 0; ii < cpi->num_stream_pid; ii++) { -+ X_FREE(cpi->entry[ii].coarse); -+- } -+- if (cpi->entry[ii].fine != NULL) { -+ X_FREE(cpi->entry[ii].fine); -+ } -++ X_FREE(cpi->entry); -+ } -+- X_FREE(cpi->entry); -+ } -+ -+ void -+@@ -654,15 +654,12 @@ clpi_free(CLPI_CL *cl) -+ if (cl == NULL) { -+ return; -+ } -+- if (cl->clip.atc_delta != NULL) { -+- X_FREE(cl->clip.atc_delta); -+- } -+- for (ii = 0; ii < cl->sequence.num_atc_seq; ii++) { -+- if (cl->sequence.atc_seq[ii].stc_seq != NULL) { -++ X_FREE(cl->clip.atc_delta); -++ if (cl->sequence.atc_seq) { -++ for (ii = 0; ii < cl->sequence.num_atc_seq; ii++) { -+ X_FREE(cl->sequence.atc_seq[ii].stc_seq); -+ } -+- } -+- if (cl->sequence.atc_seq != NULL) { -++ -+ X_FREE(cl->sequence.atc_seq); -+ } -+ -+@@ -796,7 +793,7 @@ clpi_copy(const CLPI_CL* src_cl) -+ } -+ -+ dest_cl->sequence.num_atc_seq = src_cl->sequence.num_atc_seq; -+- dest_cl->sequence.atc_seq = malloc(src_cl->sequence.num_atc_seq * sizeof(CLPI_ATC_SEQ)); -++ dest_cl->sequence.atc_seq = calloc(src_cl->sequence.num_atc_seq, sizeof(CLPI_ATC_SEQ)); -+ for (ii = 0; ii < src_cl->sequence.num_atc_seq; ii++) { -+ dest_cl->sequence.atc_seq[ii].spn_atc_start = src_cl->sequence.atc_seq[ii].spn_atc_start; -+ dest_cl->sequence.atc_seq[ii].offset_stc_id = src_cl->sequence.atc_seq[ii].offset_stc_id; -+@@ -811,7 +808,7 @@ clpi_copy(const CLPI_CL* src_cl) -+ } -+ -+ dest_cl->program.num_prog = src_cl->program.num_prog; -+- dest_cl->program.progs = malloc(src_cl->program.num_prog * sizeof(CLPI_PROG)); -++ dest_cl->program.progs = calloc(src_cl->program.num_prog, sizeof(CLPI_PROG)); -+ for (ii = 0; ii < src_cl->program.num_prog; ii++) { -+ dest_cl->program.progs[ii].spn_program_sequence_start = src_cl->program.progs[ii].spn_program_sequence_start; -+ dest_cl->program.progs[ii].program_map_pid = src_cl->program.progs[ii].program_map_pid; -+@@ -831,7 +828,7 @@ clpi_copy(const CLPI_CL* src_cl) -+ } -+ -+ dest_cl->cpi.num_stream_pid = src_cl->cpi.num_stream_pid; -+- dest_cl->cpi.entry = malloc(src_cl->cpi.num_stream_pid * sizeof(CLPI_EP_MAP_ENTRY)); -++ dest_cl->cpi.entry = calloc(src_cl->cpi.num_stream_pid, sizeof(CLPI_EP_MAP_ENTRY)); -+ for (ii = 0; ii < dest_cl->cpi.num_stream_pid; ii++) { -+ dest_cl->cpi.entry[ii].pid = src_cl->cpi.entry[ii].pid; -+ dest_cl->cpi.entry[ii].ep_stream_type = src_cl->cpi.entry[ii].ep_stream_type; -+diff --git a/src/libbluray/bdnav/index_parse.c b/src/libbluray/bdnav/index_parse.c -+index 6c07ba1..64dc5e3 100644 -+--- a/src/libbluray/bdnav/index_parse.c -++++ b/src/libbluray/bdnav/index_parse.c -+@@ -103,8 +103,16 @@ static int _parse_index(BITSTREAM *bs, INDX_ROOT *index) -+ } -+ -+ index->num_titles = bs_read(bs, 16); -++ if (!index->num_titles) { -++ BD_DEBUG(DBG_CRIT, "empty index\n"); -++ return 0; -++ } -+ -+ index->titles = calloc(index->num_titles, sizeof(INDX_TITLE)); -++ if (!index->titles) { -++ BD_DEBUG(DBG_CRIT, "out of memory\n"); -++ return 0; -++ } -+ -+ for (i = 0; i < index->num_titles; i++) { -+ -+diff --git a/src/libbluray/bdnav/meta_parse.c b/src/libbluray/bdnav/meta_parse.c -+index 50b8c75..a9a7edc 100644 -+--- a/src/libbluray/bdnav/meta_parse.c -++++ b/src/libbluray/bdnav/meta_parse.c -+@@ -81,29 +81,35 @@ static void _parseManifestNode(xmlNode * a_node, META_DL *disclib) -+ } -+ else if (xmlStrEqual(cur_node->parent->name, BAD_CAST_CONST "tableOfContents")) { -+ if (xmlStrEqual(cur_node->name, BAD_CAST_CONST "titleName") && (tmp = xmlGetProp(cur_node, BAD_CAST_CONST "titleNumber"))) { -+- int i = disclib->toc_count; -+- disclib->toc_count++; -+- disclib->toc_entries = realloc(disclib->toc_entries, (disclib->toc_count*sizeof(META_TITLE))); -+- disclib->toc_entries[i].title_number = atoi((const char*)tmp); -+- disclib->toc_entries[i].title_name = (char*)xmlNodeGetContent(cur_node); -++ META_TITLE *new_entries = realloc(disclib->toc_entries, ((disclib->toc_count + 1)*sizeof(META_TITLE))); -++ if (new_entries) { -++ int i = disclib->toc_count; -++ disclib->toc_count++; -++ disclib->toc_entries = new_entries; -++ disclib->toc_entries[i].title_number = atoi((const char*)tmp); -++ disclib->toc_entries[i].title_name = (char*)xmlNodeGetContent(cur_node); -++ } -+ XML_FREE(tmp); -+ } -+ } -+ else if (xmlStrEqual(cur_node->parent->name, BAD_CAST_CONST "description")) { -+ if (xmlStrEqual(cur_node->name, BAD_CAST_CONST "thumbnail") && (tmp = xmlGetProp(cur_node, BAD_CAST_CONST "href"))) { -+- uint8_t i = disclib->thumb_count; -+- disclib->thumb_count++; -+- disclib->thumbnails = realloc(disclib->thumbnails, (disclib->thumb_count*sizeof(META_THUMBNAIL))); -+- disclib->thumbnails[i].path = (char *)tmp; -+- if ((tmp = xmlGetProp(cur_node, BAD_CAST_CONST "size"))) { -+- int x = 0, y = 0; -+- sscanf((const char*)tmp, "%ix%i", &x, &y); -+- disclib->thumbnails[i].xres = x; -+- disclib->thumbnails[i].yres = y; -+- XML_FREE(tmp); -+- } -+- else { -+- disclib->thumbnails[i].xres = disclib->thumbnails[i].yres = -1; -++ META_THUMBNAIL *new_thumbnails = realloc(disclib->thumbnails, ((disclib->thumb_count + 1)*sizeof(META_THUMBNAIL))); -++ if (new_thumbnails) { -++ uint8_t i = disclib->thumb_count; -++ disclib->thumb_count++; -++ disclib->thumbnails = new_thumbnails; -++ disclib->thumbnails[i].path = (char *)tmp; -++ if ((tmp = xmlGetProp(cur_node, BAD_CAST_CONST "size"))) { -++ int x = 0, y = 0; -++ sscanf((const char*)tmp, "%ix%i", &x, &y); -++ disclib->thumbnails[i].xres = x; -++ disclib->thumbnails[i].yres = y; -++ XML_FREE(tmp); -++ } -++ else { -++ disclib->thumbnails[i].xres = disclib->thumbnails[i].yres = -1; -++ } -+ } -+ } -+ } -+@@ -126,15 +132,18 @@ static void _findMetaXMLfiles(META_ROOT *meta, BD_DISC *disc) -+ if (ent.d_name[0] == '.') -+ continue; -+ else if (strncasecmp(ent.d_name, "bdmt_", 5) == 0) { -+- uint8_t i = meta->dl_count; -+- meta->dl_count++; -+- meta->dl_entries = realloc(meta->dl_entries, (meta->dl_count*sizeof(META_DL))); -+- memset(&meta->dl_entries[i], 0, sizeof(meta->dl_entries[i])); -+- -+- meta->dl_entries[i].filename = str_dup(ent.d_name); -+- strncpy(meta->dl_entries[i].language_code, ent.d_name+5,3); -+- meta->dl_entries[i].language_code[3] = '\0'; -+- str_tolower(meta->dl_entries[i].language_code); -++ META_DL *new_dl_entries = realloc(meta->dl_entries, ((meta->dl_count + 1)*sizeof(META_DL))); -++ if (new_dl_entries) { -++ uint8_t i = meta->dl_count; -++ meta->dl_count++; -++ meta->dl_entries = new_dl_entries; -++ memset(&meta->dl_entries[i], 0, sizeof(meta->dl_entries[i])); -++ -++ meta->dl_entries[i].filename = str_dup(ent.d_name); -++ strncpy(meta->dl_entries[i].language_code, ent.d_name+5,3); -++ meta->dl_entries[i].language_code[3] = '\0'; -++ str_tolower(meta->dl_entries[i].language_code); -++ } -+ } -+ } -+ dir_close(dir); -+@@ -145,6 +154,10 @@ META_ROOT *meta_parse(BD_DISC *disc) -+ { -+ #ifdef HAVE_LIBXML2 -+ META_ROOT *root = calloc(1, sizeof(META_ROOT)); -++ if (!root) { -++ BD_DEBUG(DBG_CRIT, "out of memory\n"); -++ return NULL; -++ } -+ root->dl_count = 0; -+ -+ xmlDocPtr doc; +diff --git a/src/libbluray/bdnav/mpls_parse.c b/src/libbluray/bdnav/mpls_parse.c -+index da01f7b..8bfbb8c 100644 ++index e196118..87b240a 100644 +--- a/src/libbluray/bdnav/mpls_parse.c ++++ b/src/libbluray/bdnav/mpls_parse.c +@@ -39,6 +39,7 @@ @@ -77289,7 +51083,7 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + if (id2 == 2) { + // SubPath entries extension +diff --git a/src/libbluray/bdnav/mpls_parse.h b/src/libbluray/bdnav/mpls_parse.h -+index f9f7a18..94add53 100644 ++index 94bfa67..c1b2c31 100644 +--- a/src/libbluray/bdnav/mpls_parse.h ++++ b/src/libbluray/bdnav/mpls_parse.h +@@ -49,6 +49,7 @@ typedef struct @@ -77300,7 +51094,7 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + } MPLS_STREAM; + + typedef struct -+@@ -110,6 +111,7 @@ typedef struct ++@@ -109,6 +110,7 @@ typedef struct + uint8_t random_access_flag; + uint8_t audio_mix_flag; + uint8_t lossless_bypass_flag; @@ -77308,292 +51102,11 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + } MPLS_AI; + + typedef struct -+diff --git a/src/libbluray/bdnav/navigation.c b/src/libbluray/bdnav/navigation.c -+index db7fa9f..cfd7739 100644 -+--- a/src/libbluray/bdnav/navigation.c -++++ b/src/libbluray/bdnav/navigation.c -+@@ -174,6 +174,21 @@ _pl_duration(MPLS_PL *pl) -+ return duration; -+ } -+ -++static uint32_t -++_pl_chapter_count(MPLS_PL *pl) -++{ -++ unsigned ii, chapters = 0; -++ -++ // Count the number of "entry" marks (skipping "link" marks) -++ // This is the the number of chapters -++ for (ii = 0; ii < pl->mark_count; ii++) { -++ if (pl->play_mark[ii].mark_type == BD_MARK_ENTRY) { -++ chapters++; -++ } -++ } -++ return chapters; -++} -++ -+ NAV_TITLE_LIST* nav_get_title_list(BD_DISC *disc, uint32_t flags, uint32_t min_title_length) -+ { -+ BD_DIR_H *dir; -+@@ -403,15 +418,20 @@ static void _fill_clip(NAV_TITLE *title, -+ strncpy(&clip->name[5], ".m2ts", 6); -+ clip->clip_id = atoi(mpls_clip[clip->angle].clip_id); -+ -+- file = str_printf("%s.clpi", mpls_clip[clip->angle].clip_id); -+ clpi_free(clip->cl); -+- clip->cl = clpi_get(title->disc, file); -+- X_FREE(file); -++ clip->cl = NULL; -++ -++ file = str_printf("%s.clpi", mpls_clip[clip->angle].clip_id); -++ if (file) { -++ clip->cl = clpi_get(title->disc, file); -++ X_FREE(file); -++ } -+ if (clip->cl == NULL) { -+ clip->start_pkt = 0; -+ clip->end_pkt = 0; -+ return; -+ } -++ -+ switch (connection_condition) { -+ case 5: -+ case 6: -+@@ -441,7 +461,7 @@ static void _fill_clip(NAV_TITLE *title, -+ NAV_TITLE* nav_title_open(BD_DISC *disc, const char *playlist, unsigned angle) -+ { -+ NAV_TITLE *title = NULL; -+- unsigned ii, ss, chapters = 0; -++ unsigned ii, ss; -+ uint32_t pos = 0; -+ uint32_t time = 0; -+ -+@@ -501,15 +521,8 @@ NAV_TITLE* nav_title_open(BD_DISC *disc, const char *playlist, unsigned angle) -+ } -+ } -+ -+- // Count the number of "entry" marks (skipping "link" marks) -+- // This is the the number of chapters -+- for (ii = 0; ii < title->pl->mark_count; ii++) { -+- if (title->pl->play_mark[ii].mark_type == BD_MARK_ENTRY) { -+- chapters++; -+- } -+- } -+- title->chap_list.count = chapters; -+- title->chap_list.mark = calloc(chapters, sizeof(NAV_MARK)); -++ title->chap_list.count = _pl_chapter_count(title->pl); -++ title->chap_list.mark = calloc(title->chap_list.count, sizeof(NAV_MARK)); -+ title->mark_list.count = title->pl->mark_count; -+ title->mark_list.mark = calloc(title->pl->mark_count, sizeof(NAV_MARK)); -+ -+@@ -526,19 +539,29 @@ void nav_title_close(NAV_TITLE *title) -+ { -+ unsigned ii, ss; -+ -+- for (ss = 0; ss < title->sub_path_count; ss++) { -+- for (ii = 0; ii < title->sub_path[ss].clip_list.count; ii++) { -+- clpi_free(title->sub_path[ss].clip_list.clip[ii].cl); -++ if (!title) -++ return; -++ -++ if (title->sub_path) { -++ for (ss = 0; ss < title->sub_path_count; ss++) { -++ if (title->sub_path[ss].clip_list.clip) { -++ for (ii = 0; ii < title->sub_path[ss].clip_list.count; ii++) { -++ clpi_free(title->sub_path[ss].clip_list.clip[ii].cl); -++ } -++ X_FREE(title->sub_path[ss].clip_list.clip); -++ } -+ } -+- X_FREE(title->sub_path[ss].clip_list.clip); -++ X_FREE(title->sub_path); -+ } -+- X_FREE(title->sub_path); -+ -+- for (ii = 0; ii < title->pl->list_count; ii++) { -+- clpi_free(title->clip_list.clip[ii].cl); -++ if (title->clip_list.clip) { -++ for (ii = 0; ii < title->clip_list.count; ii++) { -++ clpi_free(title->clip_list.clip[ii].cl); -++ } -++ X_FREE(title->clip_list.clip); -+ } -++ -+ mpls_free(title->pl); -+- X_FREE(title->clip_list.clip); -+ X_FREE(title->chap_list.mark); -+ X_FREE(title->mark_list.mark); -+ X_FREE(title); -+diff --git a/src/libbluray/bdnav/sound_parse.c b/src/libbluray/bdnav/sound_parse.c -+index c1cbcfb..7c267da 100644 -+--- a/src/libbluray/bdnav/sound_parse.c -++++ b/src/libbluray/bdnav/sound_parse.c -+@@ -65,6 +65,7 @@ static int _sound_parse_attributes(BITSTREAM *bs, SOUND_OBJECT *obj) -+ -+ switch (i = bs_read(bs, 4)) { -+ default: BD_DEBUG(DBG_NAV, "unknown channel configuration code %d\n", i); -++ /* fall thru */ -+ case 1: obj->num_channels = 1; -+ break; -+ case 3: obj->num_channels = 2; -+@@ -72,11 +73,13 @@ static int _sound_parse_attributes(BITSTREAM *bs, SOUND_OBJECT *obj) -+ }; -+ switch (i = bs_read(bs, 4)) { -+ default: BD_DEBUG(DBG_NAV, "unknown sample rate code %d\n", i); -++ /* fall thru */ -+ case 1: obj->sample_rate = 48000; -+ break; -+ }; -+ switch (i = bs_read(bs, 2)) { -+ default: BD_DEBUG(DBG_NAV, "unknown bits per sample code %d\n", i); -++ /* fall thru */ -+ case 1: obj->bits_per_sample = 16; -+ break; -+ }; -+@@ -103,7 +106,15 @@ static int _sound_read_samples(BITSTREAM *bs, SOUND_OBJECT *obj) -+ uint32_t n; -+ uint32_t num_samples = obj->num_frames * obj->num_channels; -+ -++ if (!num_samples) { -++ return 1; -++ } -++ -+ obj->samples = calloc(num_samples, sizeof(uint16_t)); -++ if (!obj->samples) { -++ BD_DEBUG(DBG_CRIT, "out of memory\n"); -++ return 0; -++ } -+ -+ for (n = 0; n < num_samples; n++) { -+ obj->samples[n] = bs_read(bs, 16); -+@@ -116,13 +127,14 @@ void sound_free(SOUND_DATA **p) -+ { -+ if (p && *p) { -+ -+- unsigned i; -+- for (i = 0 ; i < (*p)->num_sounds; i++) { -+- X_FREE((*p)->sounds[i].samples); -+- } -+- -+- X_FREE((*p)->sounds); -++ if ((*p)->sounds) { -++ unsigned i; -++ for (i = 0 ; i < (*p)->num_sounds; i++) { -++ X_FREE((*p)->sounds[i].samples); -++ } -+ -++ X_FREE((*p)->sounds); -++ } -+ X_FREE(*p); -+ } -+ } -+@@ -150,21 +162,29 @@ static SOUND_DATA *_sound_parse(BD_FILE_H *fp) -+ bs_skip(&bs, 8); /* reserved */ -+ num_sounds = bs_read(&bs, 8); -+ -+- if (data_len < 1) { -++ if (data_len < 1 || num_sounds < 1) { -+ BD_DEBUG(DBG_NAV | DBG_CRIT, "empty database\n"); -+ goto error; -+ } -+ -+ data_offsets = calloc(num_sounds, sizeof(uint32_t)); -+ data = calloc(1, sizeof(SOUND_DATA)); -++ if (!data_offsets || !data) { -++ BD_DEBUG(DBG_CRIT, "out of memory\n"); -++ goto error; -++ } -+ data->num_sounds = num_sounds; -+ data->sounds = calloc(num_sounds, sizeof(SOUND_OBJECT)); -++ if (!data->sounds) { -++ BD_DEBUG(DBG_CRIT, "out of memory\n"); -++ goto error; -++ } -+ -+ /* parse headers */ -+ -+ for (i = 0; i < data->num_sounds; i++) { -+ if (!_sound_parse_index(&bs, data_offsets + i, &data->sounds[i])) { -+- BD_DEBUG(DBG_NAV | DBG_CRIT, "error parsing sound %d attribues\n", i); -++ BD_DEBUG(DBG_NAV | DBG_CRIT, "error parsing sound %d attributes\n", i); -+ goto error; -+ } -+ } +diff --git a/src/libbluray/bluray.c b/src/libbluray/bluray.c -+index eba9c5e..27beed7 100644 ++index 0e60b68..f633d7a 100644 +--- a/src/libbluray/bluray.c ++++ b/src/libbluray/bluray.c -+@@ -42,6 +42,7 @@ -+ #include "hdmv/hdmv_vm.h" -+ #include "hdmv/mobj_parse.h" -+ #include "decoders/graphics_controller.h" -++#include "decoders/hdmv_pids.h" -+ #include "decoders/m2ts_filter.h" -+ #include "decoders/overlay.h" -+ #include "disc/disc.h" -+@@ -93,6 +94,7 @@ typedef struct { -+ /* */ -+ uint8_t eof_hit; -+ uint8_t encrypted_block_cnt; -++ uint8_t seek_flag; /* used to fine-tune first read after seek */ -+ -+ M2TS_FILTER *m2ts_filter; -+ } BD_STREAM; -+@@ -202,7 +204,9 @@ static void _init_event_queue(BLURAY *bd) -+ { -+ if (!bd->event_queue) { -+ bd->event_queue = calloc(1, sizeof(struct bd_event_queue_s)); -+- bd_mutex_init(&bd->event_queue->mutex); -++ if (bd->event_queue) { -++ bd_mutex_init(&bd->event_queue->mutex); -++ } -+ } else { -+ bd_mutex_lock(&bd->event_queue->mutex); -+ bd->event_queue->in = 0; -+@@ -794,7 +798,15 @@ static int _preload_m2ts(BLURAY *bd, BD_PRELOAD *p) -+ -+ /* allocate buffer */ -+ p->clip_size = (size_t)st.clip_size; -+- p->buf = realloc(p->buf, p->clip_size); -++ uint8_t* tmp = (uint8_t*)realloc(p->buf, p->clip_size); -++ if (!tmp) { -++ BD_DEBUG(DBG_BLURAY | DBG_CRIT, "_preload_m2ts(): out of memory\n"); -++ _close_m2ts(&st); -++ _close_preload(p); -++ return 0; -++ } -++ -++ p->buf = tmp; -+ -+ /* read clip to buffer */ -+ -+@@ -847,6 +859,7 @@ static int64_t _seek_stream(BLURAY *bd, BD_STREAM *st, -+ } -+ -+ st->int_buf_off = 6144; -++ st->seek_flag = 1; -+ -+ return st->clip_pos; -+ } -+@@ -939,6 +952,7 @@ static void _fill_disc_info(BLURAY *bd, BD_ENC_INFO *enc_info) -+ bd->disc_info.bdplus_handled = enc_info->bdplus_handled; -+ bd->disc_info.bdplus_gen = enc_info->bdplus_gen; -+ bd->disc_info.bdplus_date = enc_info->bdplus_date; -++ bd->disc_info.no_menu_support = enc_info->no_menu_support; -+ -+ bd->disc_info.udf_volume_id = disc_volume_id(bd->disc); -+ -+@@ -1085,6 +1099,10 @@ static void _fill_disc_info(BLURAY *bd, BD_ENC_INFO *enc_info) -+ indx_free(&index); -+ } -+ -++ if (!bd->disc_info.first_play_supported || !bd->disc_info.top_menu_supported) { -++ bd->disc_info.no_menu_support = 1; -++ } -++ -+ if (bd->disc_info.bdj_detected) { -+ BDID_DATA *bdid = bdid_get(bd->disc); /* parse id.bdmv */ -+ if (bdid) { -+@@ -1624,6 +1642,25 @@ int64_t bd_seek_time(BLURAY *bd, uint64_t tick) ++@@ -1626,6 +1626,25 @@ int64_t bd_seek_time(BLURAY *bd, uint64_t tick) + return bd->s_pos; + } + @@ -77619,82 +51132,7 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + uint64_t bd_tell_time(BLURAY *bd) + { + uint32_t clip_pkt = 0, out_pkt = 0, out_time = 0; -+@@ -1956,6 +1993,19 @@ static int _bd_read(BLURAY *bd, unsigned char *buf, int len) -+ /* fatal error */ -+ return -1; -+ } -++ -++ /* finetune seek point (avoid skipping PAT/PMT/PCR) */ -++ if (BD_UNLIKELY(st->seek_flag)) { -++ st->seek_flag = 0; -++ -++ /* rewind if previous packets contain PAT/PMT/PCR */ -++ while (st->int_buf_off >= 192 && TS_PID(bd->int_buf + st->int_buf_off - 192) <= HDMV_PID_PCR) { -++ st->clip_pos -= 192; -++ st->int_buf_off -= 192; -++ bd->s_pos -= 192; -++ } -++ } -++ -+ } -+ if (size > (unsigned int)6144 - st->int_buf_off) { -+ size = 6144 - st->int_buf_off; -+@@ -2081,12 +2131,14 @@ static int _preload_textst_subpath(BLURAY *bd) -+ gc_add_font(bd->graphics_controller, NULL, -1); -+ for (ii = 0; ii < bd->st_textst.clip->cl->font_info.font_count; ii++) { -+ char *file = str_printf("%s.otf", bd->st_textst.clip->cl->font_info.font[ii].file_id); -+- uint8_t *data = NULL; -+- size_t size = disc_read_file(bd->disc, "BDMV" DIR_SEP "AUXDATA", file, &data); -+- if (data && size > 0 && gc_add_font(bd->graphics_controller, data, size) < 0) { -+- X_FREE(data); -++ if (file) { -++ uint8_t *data = NULL; -++ size_t size = disc_read_file(bd->disc, "BDMV" DIR_SEP "AUXDATA", file, &data); -++ if (data && size > 0 && gc_add_font(bd->graphics_controller, data, size) < 0) { -++ X_FREE(data); -++ } -++ X_FREE(file); -+ } -+- X_FREE(file); -+ } -+ gc_run(bd->graphics_controller, GC_CTRL_PG_CHARCODE, char_code, NULL); -+ -+@@ -2278,6 +2330,8 @@ static int _open_playlist(BLURAY *bd, const char *f_name, unsigned angle) -+ -+ _preload_subpaths(bd); -+ -++ bd->st0.seek_flag = 1; -++ -+ return 1; -+ } -+ return 0; -+@@ -2285,9 +2339,14 @@ static int _open_playlist(BLURAY *bd, const char *f_name, unsigned angle) -+ -+ int bd_select_playlist(BLURAY *bd, uint32_t playlist) -+ { -+- char *f_name = str_printf("%05d.mpls", playlist); -++ char *f_name; -+ int result; -+ -++ f_name = str_printf("%05d.mpls", playlist); -++ if (!f_name) { -++ return 0; -++ } -++ -+ bd_mutex_lock(&bd->mutex); -+ -+ if (bd->title_list) { -+@@ -2504,6 +2563,9 @@ uint32_t bd_get_titles(BLURAY *bd, uint8_t flags, uint32_t min_title_length) -+ -+ int bd_get_main_title(BLURAY *bd) -+ { -++ if (!bd) { -++ return -1; -++ } -+ if (bd->title_type != title_undef) { -+ BD_DEBUG(DBG_CRIT | DBG_BLURAY, "bd_get_main_title() can't be used with BluRay menus\n"); -+ } -+@@ -2571,6 +2633,7 @@ static BLURAY_TITLE_INFO* _fill_title_info(NAV_TITLE* title, uint32_t title_idx, ++@@ -2602,6 +2621,7 @@ static BLURAY_TITLE_INFO* _fill_title_info(NAV_TITLE* title, uint32_t title_idx, + BLURAY_CLIP_INFO *ci = &title_info->clips[ii]; + NAV_CLIP *nc = &title->clip_list.clip[ii]; + @@ -77702,7 +51140,7 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + ci->pkt_count = nc->end_pkt - nc->start_pkt; + ci->start_time = (uint64_t)nc->title_time * 2; + ci->in_time = (uint64_t)pi->in_time * 2; -+@@ -2597,6 +2660,8 @@ static BLURAY_TITLE_INFO* _fill_title_info(NAV_TITLE* title, uint32_t title_idx, ++@@ -2628,6 +2648,8 @@ static BLURAY_TITLE_INFO* _fill_title_info(NAV_TITLE* title, uint32_t title_idx, + _copy_streams(nc, ci->sec_audio_streams, pi->stn.secondary_audio, ci->sec_audio_stream_count); + } + @@ -77711,135 +51149,7 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + return title_info; + } + -+@@ -2637,9 +2702,14 @@ BLURAY_TITLE_INFO* bd_get_title_info(BLURAY *bd, uint32_t title_idx, unsigned an -+ -+ BLURAY_TITLE_INFO* bd_get_playlist_info(BLURAY *bd, uint32_t playlist, unsigned angle) -+ { -+- char *f_name = str_printf("%05d.mpls", playlist); -++ char *f_name; -+ BLURAY_TITLE_INFO *title_info; -+ -++ f_name = str_printf("%05d.mpls", playlist); -++ if (!f_name) { -++ return NULL; -++ } -++ -+ title_info = _get_title_info(bd, 0, playlist, f_name, angle); -+ -+ X_FREE(f_name); -+@@ -2694,9 +2764,9 @@ int bd_set_player_setting(BLURAY *bd, uint32_t idx, uint32_t value) -+ bd_mutex_lock(&bd->mutex); -+ -+ bd->decode_pg = !!value; -+- result = bd_psr_write_bits(bd->regs, PSR_PG_STREAM, -+- (!!value) << 31, -+- 0x80000000); -++ result = !bd_psr_write_bits(bd->regs, PSR_PG_STREAM, -++ (!!value) << 31, -++ 0x80000000); -+ -+ bd_mutex_unlock(&bd->mutex); -+ return result; -+@@ -2705,7 +2775,7 @@ int bd_set_player_setting(BLURAY *bd, uint32_t idx, uint32_t value) -+ for (i = 0; i < sizeof(map) / sizeof(map[0]); i++) { -+ if (idx == map[i].idx) { -+ bd_mutex_lock(&bd->mutex); -+- result = !bd_psr_setting_write(bd->regs, idx, value); -++ result = !bd_psr_setting_write(bd->regs, map[i].psr, value); -+ bd_mutex_unlock(&bd->mutex); -+ return result; -+ } -+@@ -2756,6 +2826,9 @@ void bd_select_stream(BLURAY *bd, uint32_t stream_type, uint32_t stream_id, uint -+ bd_mutex_lock(&bd->mutex); -+ -+ switch (stream_type) { -++ case BLURAY_AUDIO_STREAM: -++ bd_psr_write(bd->regs, PSR_PRIMARY_AUDIO_ID, stream_id & 0xff); -++ break; -+ case BLURAY_PG_TEXTST_STREAM: -+ bd_psr_write_bits(bd->regs, PSR_PG_STREAM, -+ ((!!enable_flag)<<31) | (stream_id & 0xfff), -+@@ -3076,6 +3149,11 @@ static int _play_title(BLURAY *bd, unsigned title) -+ return 0; -+ } -+ -++ if (bd->disc_info.no_menu_support) { -++ BD_DEBUG(DBG_BLURAY | DBG_CRIT, "bd_play(): no menu support\n"); -++ return 0; -++ } -++ -+ /* first play object ? */ -+ if (title == BLURAY_TITLE_FIRST_PLAY) { -+ -+@@ -3203,6 +3281,12 @@ static int _try_play_title(BLURAY *bd, unsigned title) -+ int bd_play_title(BLURAY *bd, unsigned title) -+ { -+ int ret; -++ -++ if (title == BLURAY_TITLE_TOP_MENU) { -++ /* menu call uses different UO mask */ -++ return bd_menu_call(bd, -1); -++ } -++ -+ bd_mutex_lock(&bd->mutex); -+ ret = _try_play_title(bd, title); -+ bd_mutex_unlock(&bd->mutex); -+@@ -3561,7 +3645,37 @@ int bd_get_sound_effect(BLURAY *bd, unsigned sound_id, BLURAY_SOUND_EFFECT *effe -+ } -+ -+ /* -+- * -++ * Direct file access -++ */ -++ -++static int _bd_read_file(BLURAY *bd, const char *dir, const char *file, void **data, int64_t *size) -++{ -++ if (!bd || !bd->disc || !file || !data || !size) { -++ BD_DEBUG(DBG_CRIT, "Invalid arguments for bd_read_file()\n"); -++ return 0; -++ } -++ -++ *data = NULL; -++ *size = (int64_t)disc_read_file(bd->disc, dir, file, (uint8_t**)data); -++ if (!*data || *size < 0) { -++ BD_DEBUG(DBG_BLURAY, "bd_read_file() failed\n"); -++ X_FREE(*data); -++ return 0; -++ } -++ -++ BD_DEBUG(DBG_BLURAY, "bd_read_file(): read %"PRId64" bytes from %s"DIR_SEP"%s\n", -++ *size, dir, file); -++ return 1; -++} -++ -++int bd_read_file(BLURAY *bd, const char *path, void **data, int64_t *size) -++{ -++ return _bd_read_file(bd, NULL, path, data, size); -++} -++ -++ -++/* -++ * Metadata -+ */ -+ -+ const struct meta_dl *bd_get_meta(BLURAY *bd) -+@@ -3598,6 +3712,15 @@ const struct meta_dl *bd_get_meta(BLURAY *bd) -+ return meta; -+ } -+ -++int bd_get_meta_file(BLURAY *bd, const char *name, void **data, int64_t *size) -++{ -++ return _bd_read_file(bd, DIR_SEP "BDMV" DIR_SEP "META" DIR_SEP "DL", name, data, size); -++} -++ -++/* -++ * Database access -++ */ -++ -+ struct clpi_cl *bd_get_clpi(BLURAY *bd, unsigned clip_ref) -+ { -+ if (bd->title && clip_ref < bd->title->clip_list.count) { -+@@ -3655,3 +3778,28 @@ void bd_free_bdjo(struct bdjo_data *obj) ++@@ -3746,3 +3768,28 @@ void bd_free_bdjo(struct bdjo_data *obj) + (void)obj; + #endif + } @@ -77869,7 +51179,7 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 ++ return NULL; ++} +diff --git a/src/libbluray/bluray.h b/src/libbluray/bluray.h -+index 6ade74b..6e74df4 100644 ++index cbf16fc..97dc1a3 100644 +--- a/src/libbluray/bluray.h ++++ b/src/libbluray/bluray.h +@@ -32,6 +32,7 @@ extern "C" { @@ -77880,17 +51190,7 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + + #define TITLES_ALL 0 /**< all titles. */ + #define TITLES_FILTER_DUP_TITLE 0x01 /**< remove duplicate titles. */ -+@@ -119,6 +120,9 @@ typedef struct { -+ char bdj_disc_id[33]; /* (BD-J) disc ID */ -+ -+ const char *udf_volume_id; /* optional UDF volume identifier */ -++ -++ uint8_t no_menu_support; /* 1 if this disc can't be played using on-disc menus */ -++ -+ } BLURAY_DISC_INFO; -+ -+ /* -+@@ -216,6 +220,7 @@ typedef struct bd_stream_info { ++@@ -225,6 +226,7 @@ typedef struct bd_stream_info { + } BLURAY_STREAM_INFO; + + typedef struct bd_clip { @@ -77898,7 +51198,7 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + uint32_t pkt_count; + uint8_t still_mode; + uint16_t still_time; /* seconds */ -+@@ -266,6 +271,8 @@ typedef struct bd_title_info { ++@@ -275,6 +277,8 @@ typedef struct bd_title_info { + + uint32_t mark_count; + BLURAY_TITLE_MARK *marks; @@ -77907,37 +51207,7 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + } BLURAY_TITLE_INFO; + + /* -+@@ -355,12 +362,29 @@ const BLURAY_DISC_INFO *bd_get_disc_info(BLURAY *bd); -+ * If information is provided in multiple languages, currently -+ * selected language (BLURAY_PLAYER_SETTING_MENU_LANG) is used. -+ * -++ * Referenced thumbnail images should be read with bd_get_meta_file(). -++ * -+ * @param bd BLURAY object -+ * @return META_DL (disclib) object, NULL on error -+ */ -+ struct meta_dl; -+ const struct meta_dl *bd_get_meta(BLURAY *bd); -+ -++/** -++ * -++ * Read metadata file from BluRay disc. -++ * -++ * Allocate large enough memory block and read file contents. -++ * Caller must free the memory block with free(). -++ * -++ * @param bd BLURAY object -++ * @param file_name name of metadata file -++ * @param data where to store pointer to file data -++ * @param size where to store file size -++ * @return 1 on success, 0 on error -++ */ -++int bd_get_meta_file(BLURAY *bd, const char *file_name, void **data, int64_t *size); -++ -+ -+ /* -+ * Title selection without on-disc menus -+@@ -441,6 +465,16 @@ uint32_t bd_get_current_title(BLURAY *bd); ++@@ -483,6 +487,16 @@ uint32_t bd_get_current_title(BLURAY *bd); + + /** + * @@ -77954,15 +51224,7 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + * Read from currently selected title file, decrypt if possible + * + * @param bd BLURAY object -+@@ -536,6 +570,7 @@ void bd_seamless_angle_change(BLURAY *bd, unsigned angle); -+ * @param stream_id stream number (1..N) -+ * @param enable_flag set to 0 to disable streams of this type -+ */ -++#define BLURAY_AUDIO_STREAM 0 -+ #define BLURAY_PG_TEXTST_STREAM 1 -+ -+ void bd_select_stream(BLURAY *bd, uint32_t stream_type, uint32_t stream_id, uint32_t enable_flag); -+@@ -963,7 +998,6 @@ int bd_mouse_select(BLURAY *bd, int64_t pts, uint16_t x, uint16_t y); ++@@ -1007,7 +1021,6 @@ int bd_mouse_select(BLURAY *bd, int64_t pts, uint16_t x, uint16_t y); + + /* access to internal information */ + @@ -77970,27 +51232,12 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + /** + * + * Get copy of clip information for requested playitem. -+@@ -1001,6 +1035,43 @@ void bd_free_bdjo(struct bdjo_data *); -+ int bd_start_bdj(BLURAY *bd, const char* start_object); // start BD-J from the specified BD-J object (should be a 5 character string) -+ void bd_stop_bdj(BLURAY *bd); // shutdown BD-J and clean up resources ++@@ -1060,6 +1073,28 @@ void bd_stop_bdj(BLURAY *bd); // shutdown BD-J and clean up resources ++ */ ++ int bd_read_file(BLURAY *, const char *path, void **data, int64_t *size); + ++/** ++ * -++ * Read a file from BluRay Virtual File System. -++ * -++ * Allocate large enough memory block and read file contents. -++ * Caller must free the memory block with free(). -++ * -++ * @param bd BLURAY object -++ * @param file_name path to the file (relative to disc root) -++ * @param data where to store pointer to allocated data -++ * @param size where to store file size -++ * @return 1 on success, 0 on error -++ */ -++int bd_read_file(BLURAY *, const char *path, void **data, int64_t *size); -++ -++/** -++ * ++ * Get information about the clip ++ * ++ * @param bd BLURAY object @@ -78014,527 +51261,24 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + + #ifdef __cplusplus + } -+diff --git a/src/libbluray/decoders/graphics_controller.c b/src/libbluray/decoders/graphics_controller.c -+index dabde1c..d3c775a 100644 -+--- a/src/libbluray/decoders/graphics_controller.c -++++ b/src/libbluray/decoders/graphics_controller.c -+@@ -825,6 +825,8 @@ void gc_free(GRAPHICS_CONTROLLER **p) -+ -+ bd_mutex_destroy(&gc->mutex); -+ -++ X_FREE(gc->saved_bog_data); -++ -+ X_FREE(*p); -+ } -+ } -+diff --git a/src/libbluray/decoders/hdmv_pids.h b/src/libbluray/decoders/hdmv_pids.h -+index ac5bc6a..45a55f3 100644 -+--- a/src/libbluray/decoders/hdmv_pids.h -++++ b/src/libbluray/decoders/hdmv_pids.h -+@@ -61,5 +61,12 @@ -+ #define IS_HDMV_PID_IG(pid) ((pid) >= HDMV_PID_IG_FIRST && (pid) <= HDMV_PID_IG_LAST) -+ #define IS_HDMV_PID_TEXTST(pid) ((pid) == HDMV_PID_TEXTST) -+ -++/* -++ * Extract PID from HDMV MPEG-TS packet -++ */ -++ -++#define TS_PID(buf) \ -++ ((((buf)[4+1] & 0x1f) << 8) | (buf)[4+2]) -++ -+ -+ #endif // _HDMV_PIDS_H_ -+diff --git a/src/libbluray/decoders/overlay.h b/src/libbluray/decoders/overlay.h -+index 6a31218..7daa478 100644 -+--- a/src/libbluray/decoders/overlay.h -++++ b/src/libbluray/decoders/overlay.h -+@@ -20,6 +20,10 @@ -+ #ifndef BD_OVERLAY_H_ -+ #define BD_OVERLAY_H_ -+ -++#ifdef __cplusplus -++extern "C" { -++#endif -++ -+ #include <stdint.h> -+ -+ #define BD_OVERLAY_INTERFACE_VERSION 2 -+@@ -199,4 +203,8 @@ typedef struct bd_argb_buffer_s { -+ -+ } BD_ARGB_BUFFER; -+ -++#ifdef __cplusplus -++} -++#endif -++ -+ #endif // BD_OVERLAY_H_ -+diff --git a/src/libbluray/decoders/textst_render.c b/src/libbluray/decoders/textst_render.c -+index 8d1527e..0e87d4b 100644 -+--- a/src/libbluray/decoders/textst_render.c -++++ b/src/libbluray/decoders/textst_render.c -+@@ -74,6 +74,10 @@ TEXTST_RENDER *textst_render_init(void) -+ #ifdef HAVE_FT2 -+ TEXTST_RENDER *p = calloc(1, sizeof(TEXTST_RENDER)); -+ -++ if (!p) { -++ return NULL; -++ } -++ -+ if (!FT_Init_FreeType(&p->ft_lib)) { -+ return p; -+ } -+diff --git a/src/libbluray/disc/aacs.c b/src/libbluray/disc/aacs.c -+index 217ef6f..9ae8efb 100644 -+--- a/src/libbluray/disc/aacs.c -++++ b/src/libbluray/disc/aacs.c -+@@ -47,6 +47,8 @@ struct bd_aacs { -+ fptr_p_void get_device_binding_id; -+ fptr_p_void get_device_nonce; -+ fptr_p_void get_media_key; -++ -++ int impl_id; -+ }; -+ -+ -+@@ -58,15 +60,19 @@ static void _libaacs_close(BD_AACS *p) -+ } -+ } -+ -+-void libaacs_unload(BD_AACS **p) -++static void _unload(BD_AACS *p) -+ { -+- if (p && *p) { -+- _libaacs_close(*p); -++ _libaacs_close(p); -+ -+- if ((*p)->h_libaacs) { -+- dl_dlclose((*p)->h_libaacs); -+- } -++ if (p->h_libaacs) { -++ dl_dlclose(p->h_libaacs); -++ } -++} -+ -++void libaacs_unload(BD_AACS **p) -++{ -++ if (p && *p) { -++ _unload(*p); -+ X_FREE(*p); -+ } -+ } -+@@ -82,7 +88,7 @@ int libaacs_required(void *have_file_handle, int (*have_file)(void *, const char -+ return 0; -+ } -+ -+-static void *_open_libaacs(void) -++static void *_open_libaacs(int *impl_id) -+ { -+ const char * const libaacs[] = { -+ getenv("LIBAACS_PATH"), -+@@ -91,10 +97,11 @@ static void *_open_libaacs(void) -+ }; -+ unsigned ii; -+ -+- for (ii = 0; ii < sizeof(libaacs) / sizeof(libaacs[0]); ii++) { -++ for (ii = *impl_id; ii < sizeof(libaacs) / sizeof(libaacs[0]); ii++) { -+ if (libaacs[ii]) { -+ void *handle = dl_dlopen(libaacs[ii], "0"); -+ if (handle) { -++ *impl_id = ii; -+ BD_DEBUG(DBG_BLURAY, "Using %s for AACS\n", libaacs[ii]); -+ return handle; -+ } -+@@ -105,11 +112,15 @@ static void *_open_libaacs(void) -+ return NULL; -+ } -+ -+-BD_AACS *libaacs_load(void) -++static BD_AACS *_load(int impl_id) -+ { -+ BD_AACS *p = calloc(1, sizeof(BD_AACS)); -++ if (!p) { -++ return NULL; -++ } -++ p->impl_id = impl_id; -+ -+- p->h_libaacs = _open_libaacs(); -++ p->h_libaacs = _open_libaacs(&p->impl_id); -+ if (!p->h_libaacs) { -+ X_FREE(p); -+ return NULL; -+@@ -140,6 +151,11 @@ BD_AACS *libaacs_load(void) -+ return p; -+ } -+ -++BD_AACS *libaacs_load(void) -++{ -++ return _load(0); -++} -++ -+ int libaacs_open(BD_AACS *p, const char *device, -+ void *file_open_handle, void *file_open_fp, -+ const char *keyfile_path) -+@@ -177,6 +193,22 @@ int libaacs_open(BD_AACS *p, const char *device, -+ BD_DEBUG(DBG_BLURAY, "aacs_open() not found\n"); -+ } -+ -++ if (error_code) { -++ /* failed. try next aacs implementation if available. */ -++ BD_AACS *p2 = _load(p->impl_id + 1); -++ if (p2) { -++ if (!libaacs_open(p2, device, file_open_handle, file_open_fp, keyfile_path)) { -++ /* succeed - swap implementations */ -++ _unload(p); -++ *p = *p2; -++ X_FREE(p2); -++ return 0; -++ } -++ /* failed - report original errors */ -++ libaacs_unload(&p2); -++ } -++ } -++ -+ if (p->aacs) { -+ if (aacs_get_mkb_version) { -+ p->mkbv = aacs_get_mkb_version(p->aacs); -+diff --git a/src/libbluray/disc/bdplus.c b/src/libbluray/disc/bdplus.c -+index b8c4d57..363719f 100644 -+--- a/src/libbluray/disc/bdplus.c -++++ b/src/libbluray/disc/bdplus.c -+@@ -107,6 +107,9 @@ static void *_libbdplus_open(void) -+ BD_BDPLUS *libbdplus_load(void) -+ { -+ BD_BDPLUS *p = calloc(1, sizeof(BD_BDPLUS)); -++ if (!p) { -++ return NULL; -++ } -+ -+ BD_DEBUG(DBG_BDPLUS, "attempting to load libbdplus\n"); -+ -+@@ -241,10 +244,12 @@ BD_BDPLUS_ST *libbdplus_m2ts(BD_BDPLUS *p, uint32_t clip_id, uint64_t pos) -+ if (!p->m2ts) { -+ /* use old API */ -+ BD_BDPLUS_ST *ret = calloc(1, sizeof(BD_BDPLUS_ST)); -+- ret->lib = p; -+- ret->st = NULL; -+- p->title(p->bdplus, clip_id); -+- p->seek(p->bdplus, pos); -++ if (ret) { -++ ret->lib = p; -++ ret->st = NULL; -++ p->title(p->bdplus, clip_id); -++ p->seek(p->bdplus, pos); -++ } -+ return ret; -+ } -+ -+@@ -258,9 +263,11 @@ BD_BDPLUS_ST *libbdplus_m2ts(BD_BDPLUS *p, uint32_t clip_id, uint64_t pos) -+ p->m2ts_close(st); -+ } else { -+ BD_BDPLUS_ST *ret = calloc(1, sizeof(BD_BDPLUS_ST)); -+- ret->lib = p; -+- ret->st = st; -+- BD_DEBUG(DBG_BLURAY | DBG_CRIT, "BD+ active for clip %05d.m2ts\n", clip_id); -++ if (ret) { -++ ret->lib = p; -++ ret->st = st; -++ BD_DEBUG(DBG_BLURAY | DBG_CRIT, "BD+ active for clip %05d.m2ts\n", clip_id); -++ } -+ return ret; -+ } -+ } -+diff --git a/src/libbluray/disc/dec.c b/src/libbluray/disc/dec.c -+index 694646e..1c8a601 100644 -+--- a/src/libbluray/disc/dec.c -++++ b/src/libbluray/disc/dec.c -+@@ -158,6 +158,10 @@ static int _bdrom_have_file(void *p, const char *dir, const char *file) -+ char *path; -+ -+ path = str_printf("%s" DIR_SEP "%s", dir, file); -++ if (!path) { -++ return 0; -++ } -++ -+ fp = dev->pf_file_open_bdrom(dev->file_open_bdrom_handle, path); -+ X_FREE(path); -+ -+@@ -175,6 +179,8 @@ static int _libaacs_init(BD_DEC *dec, struct dec_dev *dev, -+ int result; -+ const uint8_t *disc_id; -+ -++ memset(i, 0, sizeof(*i)); -++ -+ libaacs_unload(&dec->aacs); -+ -+ i->aacs_detected = libaacs_required((void*)dev, _bdrom_have_file); -+@@ -201,7 +207,7 @@ static int _libaacs_init(BD_DEC *dec, struct dec_dev *dev, -+ } -+ -+ if (result) { -+- BD_DEBUG(DBG_BLURAY | DBG_CRIT, "aacs_open() failed!\n"); -++ BD_DEBUG(DBG_BLURAY | DBG_CRIT, "aacs_open() failed: %d!\n", result); -+ libaacs_unload(&dec->aacs); -+ return 0; -+ } -+@@ -255,6 +261,13 @@ static int _libbdplus_init(BD_DEC *dec, struct dec_dev *dev, -+ i->bdplus_gen = libbdplus_get_gen(dec->bdplus); -+ i->bdplus_date = libbdplus_get_date(dec->bdplus); -+ i->bdplus_handled = 1; -++ -++ if (i->bdplus_date == 0) { -++ // libmmbd -> no menu support -++ BD_DEBUG(DBG_BLURAY | DBG_CRIT, "WARNING: using libmmbd for BD+. On-disc menus will not work.\n"); -++ i->no_menu_support = 1; -++ } -++ -+ return 1; -+ } -+ +diff --git a/src/libbluray/disc/disc.c b/src/libbluray/disc/disc.c -+index ecd53e3..757b6ed 100644 ++index defa084..375e6c3 100644 +--- a/src/libbluray/disc/disc.c ++++ b/src/libbluray/disc/disc.c -+@@ -65,7 +65,11 @@ static BD_FILE_H *_bdrom_open_path(void *p, const char *rel_path) -+ char *abs_path; ++@@ -69,7 +69,7 @@ static BD_FILE_H *_bdrom_open_path(void *p, const char *rel_path) ++ return NULL; ++ } + -+ abs_path = str_printf("%s%s", disc->disc_root, rel_path); +- fp = file_open(abs_path, "rb"); -++ if (!abs_path) { -++ return NULL; -++ } -++ ++ fp = file_open(abs_path, "rbS"); + X_FREE(abs_path); + + return fp; -+@@ -78,6 +82,10 @@ static BD_DIR_H *_bdrom_open_dir(void *p, const char *dir) -+ char *path; -+ -+ path = str_printf("%s%s", disc->disc_root, dir); -++ if (!path) { -++ return NULL; -++ } -++ -+ dp = dir_open(path); -+ X_FREE(path); -+ -+@@ -96,8 +104,10 @@ static BD_FILE_H *_overlay_open_path(BD_DISC *p, const char *rel_path) -+ -+ if (p->overlay_root) { -+ char *abs_path = str_printf("%s%s", p->overlay_root, rel_path); -+- fp = file_open(abs_path, "rb"); -+- X_FREE(abs_path); -++ if (abs_path) { -++ fp = file_open(abs_path, "rb"); -++ X_FREE(abs_path); -++ } -+ } -+ -+ bd_mutex_unlock(&p->ovl_mutex); -+@@ -113,8 +123,10 @@ static BD_DIR_H *_overlay_open_dir(BD_DISC *p, const char *dir) -+ -+ if (p->overlay_root) { -+ char *abs_path = str_printf("%s%s", p->disc_root, dir); -+- dp = dir_open_default()(abs_path); -+- X_FREE(abs_path); -++ if (abs_path) { -++ dp = dir_open_default()(abs_path); -++ X_FREE(abs_path); -++ } -+ } -+ -+ bd_mutex_unlock(&p->ovl_mutex); -+@@ -165,7 +177,7 @@ static void _comb_dir_append(BD_DIR_H *dp, BD_DIRENT *entry) -+ } -+ -+ /* append */ -+- priv = realloc(priv, sizeof(*priv) + priv->count * sizeof(BD_DIRENT)); -++ priv = realloc(dp->internal, sizeof(*priv) + priv->count * sizeof(BD_DIRENT)); -+ if (!priv) { -+ return; -+ } -+@@ -183,6 +195,10 @@ static BD_DIR_H *_combine_dirs(BD_DIR_H *ovl, BD_DIR_H *rom) -+ dp->read = _comb_dir_read; -+ dp->close = _comb_dir_close; -+ dp->internal = calloc(1, sizeof(COMB_DIR)); -++ if (!dp->internal) { -++ X_FREE(dp); -++ goto out; -++ } -+ -+ while (!dir_read(ovl, &entry)) { -+ _comb_dir_append(dp, &entry); -+@@ -191,6 +207,8 @@ static BD_DIR_H *_combine_dirs(BD_DIR_H *ovl, BD_DIR_H *rom) -+ _comb_dir_append(dp, &entry); -+ } -+ } -++ -++ out: -+ dir_close(ovl); -+ dir_close(rom); -+ -+@@ -342,6 +360,10 @@ BD_FILE_H *disc_open_file(BD_DISC *p, const char *dir, const char *file) -+ char *path; -+ -+ path = str_printf("%s" DIR_SEP "%s", dir, file); -++ if (!path) { -++ return NULL; -++ } -++ -+ fp = disc_open_path(p, path); -+ X_FREE(path); -+ -+@@ -377,7 +399,11 @@ size_t disc_read_file(BD_DISC *disc, const char *dir, const char *file, -+ -+ *data = NULL; -+ -+- fp = disc_open_file(disc, dir, file); -++ if (dir) { -++ fp = disc_open_file(disc, dir, file); -++ } else { -++ fp = disc_open_path(disc, file); -++ } -+ if (!fp) { -+ return 0; -+ } -+@@ -454,7 +480,7 @@ int disc_cache_bdrom_file(BD_DISC *p, const char *rel_path, const char *cache_pa -+ BD_DEBUG(DBG_FILE | DBG_CRIT, "error caching file %s\n", rel_path); -+ file_close(fp_out); -+ file_close(fp_in); -+- file_unlink(cache_path); -++ (void)file_unlink(cache_path); -+ return -1; -+ } -+ } -+diff --git a/src/libbluray/disc/enc_info.h b/src/libbluray/disc/enc_info.h -+index d45d891..47ca94f 100644 -+--- a/src/libbluray/disc/enc_info.h -++++ b/src/libbluray/disc/enc_info.h -+@@ -34,6 +34,8 @@ typedef struct bd_enc_info { -+ uint8_t disc_id[20]; -+ uint8_t bdplus_gen; -+ uint32_t bdplus_date; -++ -++ uint8_t no_menu_support; -+ } BD_ENC_INFO; -+ -+ #endif /* _BD_DISC_ENC_INFO_H_ */ -+diff --git a/src/libbluray/disc/udf_fs.c b/src/libbluray/disc/udf_fs.c -+index 1eec761..3e438ca 100644 -+--- a/src/libbluray/disc/udf_fs.c -++++ b/src/libbluray/disc/udf_fs.c -+@@ -67,6 +67,9 @@ static int64_t _file_read(BD_FILE_H *file, uint8_t *buf, int64_t size) -+ BD_FILE_H *udf_file_open(void *udf, const char *filename) -+ { -+ BD_FILE_H *file = calloc(1, sizeof(BD_FILE_H)); -++ if (!file) { -++ return NULL; -++ } -+ -+ BD_DEBUG(DBG_FILE, "Opening UDF file %s... (%p)\n", filename, (void*)file); -+ -+@@ -116,6 +119,9 @@ static int _dir_read(BD_DIR_H *dir, BD_DIRENT *entry) -+ BD_DIR_H *udf_dir_open(void *udf, const char* dirname) -+ { -+ BD_DIR_H *dir = calloc(1, sizeof(BD_DIR_H)); -++ if (!dir) { -++ return NULL; -++ } -+ -+ BD_DEBUG(DBG_DIR, "Opening UDF dir %s... (%p)\n", dirname, (void*)dir); -+ -+diff --git a/src/libbluray/hdmv/mobj_print.c b/src/libbluray/hdmv/mobj_print.c -+index 5c5313e..4361a76 100644 -+--- a/src/libbluray/hdmv/mobj_print.c -++++ b/src/libbluray/hdmv/mobj_print.c -+@@ -159,6 +159,7 @@ static const char * const psr_info[128] = { -+ /* PSR127 */ NULL, -+ }; -+ -++#if 0 -+ static const char * const insn_groups[4] = { -+ "BRANCH", -+ "COMPARE", -+@@ -175,6 +176,7 @@ static const char * const insn_group_set[8] = { -+ "SET", -+ "SETSYSTEM", -+ }; -++#endif -+ -+ static const char * const insn_opt_set[32] = { -+ NULL, -+diff --git a/src/util/logging.c b/src/util/logging.c -+index b8ef1f5..62e6b59 100644 -+--- a/src/util/logging.c -++++ b/src/util/logging.c -+@@ -81,19 +81,34 @@ void bd_debug(const char *file, int line, uint32_t mask, const char *format, ... -+ -+ if (mask & debug_mask) { -+ const char *f = strrchr(file, DIR_SEP_CHAR); -+- char buffer[4096], *pt = buffer; -++ char buffer[4096]; -+ va_list args; -++ int len, len2; -+ -+- pt += sprintf(buffer, "%s:%d: ", f ? f + 1 : file, line); -++ len = sprintf(buffer, "%s:%d: ", f ? f + 1 : file, line); -++ if (len < 0) { -++ return; -++ } -+ -+ va_start(args, format); -+- vsnprintf(pt, sizeof(buffer) - (size_t)(intptr_t)(pt - buffer) - 1, format, args); -++ len2 = vsnprintf(buffer + len, sizeof(buffer) - len - 1, format, args); -+ va_end(args); -+ -++ if (len2 < 0) { -++ return; -++ } -++ -+ if (log_func) { -++ buffer[sizeof(buffer)-1] = 0; -+ log_func(buffer); -++ -+ } else { -+- fprintf(logfile, "%s", buffer); -++ len += len2; -++ if ((size_t)len >= sizeof(buffer)) { -++ len = sizeof(buffer); -++ } -++ -++ fwrite(buffer, len, 1, logfile); -+ } -+ } -+ } -+diff --git a/src/util/refcnt.h b/src/util/refcnt.h -+index b839eba..9164921 100644 -+--- a/src/util/refcnt.h -++++ b/src/util/refcnt.h -+@@ -20,6 +20,10 @@ -+ #ifndef BD_REFCNT_H_ -+ #define BD_REFCNT_H_ -+ -++#ifdef __cplusplus -++extern "C" { -++#endif -++ -+ #include "attributes.h" -+ -+ #include <stddef.h> -+@@ -53,4 +57,8 @@ void bd_refcnt_inc(const void *obj); -+ void bd_refcnt_dec(const void *obj); -+ #endif -+ -++#ifdef __cplusplus -++} -++#endif -++ -+ #endif // BD_REFCNT_H_ -From 5e19f7192303245587548c2564d1e1711019a565 Mon Sep 17 00:00:00 2001 +From b1af1a3caed688d7690a40b24f3db8480c415382 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Wed, 2 Mar 2016 19:40:47 +0000 -Subject: [PATCH 48/67] [VideoPlayer] Added new msdk-mvc decoder. +Subject: [PATCH 46/61] [VideoPlayer] Added new msdk-mvc decoder. --- xbmc/cores/VideoPlayer/DVDCodecs/DVDCodecUtils.cpp | 61 ++++++++++++++++++++++ @@ -78650,10 +51394,10 @@ index eb76a6fe73f6c884540807cfb93c7a3ecc4eea90..7e24c2364e8d2efa9b8351afc041aa14 static int PixfmtFromEFormat(ERenderFormat format); }; -From 38596e0f01d1235fe66c4891818f203e676bf6af Mon Sep 17 00:00:00 2001 +From 411ae88ce803806ae1581960ba2c2f4a7474164a Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Sun, 6 Mar 2016 12:54:59 +0000 -Subject: [PATCH 49/67] mvc: Automatically enable stereo mode +Subject: [PATCH 47/61] mvc: Automatically enable stereo mode --- xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp | 6 +++++- @@ -78661,10 +51405,10 @@ Subject: [PATCH 49/67] mvc: Automatically enable stereo mode 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -index 8691b086a46fcdd03eee809a53ea9b20f74dcc05..b4e2c57d406297f75c5dfc0217f4d33507cb6755 100644 +index 283b2626731c25c67e4c065dac7725a488c09523..a253b7fe8c591ba318958ea133355febb24ab328 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -@@ -571,13 +571,17 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) +@@ -397,13 +397,17 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) switch (hints.codec) { case AV_CODEC_ID_H264: @@ -78684,10 +51428,10 @@ index 8691b086a46fcdd03eee809a53ea9b20f74dcc05..b4e2c57d406297f75c5dfc0217f4d335 break; case AV_CODEC_ID_H263: diff --git a/xbmc/cores/omxplayer/OMXVideo.cpp b/xbmc/cores/omxplayer/OMXVideo.cpp -index b2bb0a832f5a722bb9de2a48e21e96d5d74e71b8..f8f26a891f6610de83ec143ec4b51f0aea5424de 100644 +index 311dd6689236d660919c4c4483c51dca2752514a..536332c43e22ccb229e72b88518e54dd8a23ac41 100644 --- a/xbmc/cores/omxplayer/OMXVideo.cpp +++ b/xbmc/cores/omxplayer/OMXVideo.cpp -@@ -401,6 +401,7 @@ bool COMXVideo::Open(CDVDStreamInfo &hints, OMXClock *clock, EDEINTERLACEMODE de +@@ -398,6 +398,7 @@ bool COMXVideo::Open(CDVDStreamInfo &hints, OMXClock *clock, bool hdmi_clock_syn switch (hints.codec) { case AV_CODEC_ID_H264: @@ -78695,7 +51439,7 @@ index b2bb0a832f5a722bb9de2a48e21e96d5d74e71b8..f8f26a891f6610de83ec143ec4b51f0a { switch(hints.profile) { -@@ -437,10 +438,13 @@ bool COMXVideo::Open(CDVDStreamInfo &hints, OMXClock *clock, EDEINTERLACEMODE de +@@ -434,10 +435,13 @@ bool COMXVideo::Open(CDVDStreamInfo &hints, OMXClock *clock, bool hdmi_clock_syn break; } } @@ -78711,10 +51455,10 @@ index b2bb0a832f5a722bb9de2a48e21e96d5d74e71b8..f8f26a891f6610de83ec143ec4b51f0a break; case AV_CODEC_ID_MPEG4: -From 25afb65c978ae78c35cfcfd10cb355ba88d42f7a Mon Sep 17 00:00:00 2001 +From b8c71a30f6d8625f52099abcb71d24fe60a5e250 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Thu, 24 Mar 2016 13:02:58 +0000 -Subject: [PATCH 50/67] ffmpeg: mvc: fix for pixelation from packets with no +Subject: [PATCH 48/61] ffmpeg: mvc: fix for pixelation from packets with no pts/dts --- @@ -78776,10 +51520,10 @@ index 92d9437b36eaa4e655990f7e68634e0bbf4d9605..99f375ba5d5b40eecdd423ac5787276e cd $(PLATFORM);\ CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" CPPFLAGS="$(CPPFLAGS)" LDFLAGS="$(LDFLAGS)" \ -From bcc3e1b01501c7ca65525ae31ecdb7a6028f8e84 Mon Sep 17 00:00:00 2001 +From e6e26007a7508bb472e8da389a0718a8c33515b3 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Wed, 9 Mar 2016 13:08:44 +0000 -Subject: [PATCH 51/67] stereoscopicmanager: remove hardwarebased for rbp +Subject: [PATCH 49/61] stereoscopicmanager: remove hardwarebased for rbp --- xbmc/guilib/StereoscopicsManager.cpp | 2 ++ @@ -78801,10 +51545,10 @@ index 6eb0752994bc5f8c47efbbf211120af0a0720d0c..9426604f6460651f54cc035476e69530 { "mvc_rl", RENDER_STEREO_MODE_SPLIT_HORIZONTAL }, // fallback {} -From 5ca0d3a5d247af35d48a4375131117466ad56f09 Mon Sep 17 00:00:00 2001 +From 6a0689238dba27ebab5eb725bc1347e0cf54f653 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Tue, 17 May 2016 19:24:08 +0100 -Subject: [PATCH 52/67] stereoscopics: Switch to using block_lr for mvc to +Subject: [PATCH 50/61] stereoscopics: Switch to using block_lr for mvc to match makemkv See: http://forum.kodi.tv/showthread.php?tid=221407&pid=2339656#pid2339656 @@ -78817,10 +51561,10 @@ See: http://forum.kodi.tv/showthread.php?tid=221407&pid=2339656#pid2339656 5 files changed, 12 insertions(+), 17 deletions(-) diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -index b4e2c57d406297f75c5dfc0217f4d33507cb6755..470083b2256d23488ca476cebfe8d3ef9f62377e 100644 +index a253b7fe8c591ba318958ea133355febb24ab328..1bab467cee97cad4a05fec71f29ca72d3ca93581 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -@@ -581,7 +581,7 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) +@@ -407,7 +407,7 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) m_codingType = MMAL_ENCODING_MVC; m_pFormatName= "mmal-mvc"; if (hints.stereo_mode == "mono") @@ -78830,10 +51574,10 @@ index b4e2c57d406297f75c5dfc0217f4d33507cb6755..470083b2256d23488ca476cebfe8d3ef break; case AV_CODEC_ID_H263: diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -index 54e4d0b66680a08c1e4c1be343fabe4371aec6af..5798ba2ede172c89d18b6997874117301a8b6a37 100644 +index 65d998f65493c1b463a4d1cabf36a16c9a06d498..815dc7589fed03a5d448297df5ebddd24daef80d 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -@@ -1387,7 +1387,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) +@@ -1400,7 +1400,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) CDVDInputStreamBluray *bluRay = static_cast<CDVDInputStreamBluray*>(m_pInput); if (bluRay->HasMVC()) { @@ -78873,10 +51617,10 @@ index 04ceed1504c2d81aaa165d232e128c410b9fdc2c..49f7f7ca7e144a259f6d06bd11cd97aa std::string res = convert[mode]; if(res.empty()) diff --git a/xbmc/cores/omxplayer/OMXVideo.cpp b/xbmc/cores/omxplayer/OMXVideo.cpp -index f8f26a891f6610de83ec143ec4b51f0aea5424de..de15bfff05d23949d6e6f4304b15aa7d79120dc2 100644 +index 536332c43e22ccb229e72b88518e54dd8a23ac41..39bc0530cecd54ae8c3a5481c92f1a6a18a4d9c5 100644 --- a/xbmc/cores/omxplayer/OMXVideo.cpp +++ b/xbmc/cores/omxplayer/OMXVideo.cpp -@@ -444,7 +444,7 @@ bool COMXVideo::Open(CDVDStreamInfo &hints, OMXClock *clock, EDEINTERLACEMODE de +@@ -441,7 +441,7 @@ bool COMXVideo::Open(CDVDStreamInfo &hints, OMXClock *clock, bool hdmi_clock_syn m_codingType = OMX_VIDEO_CodingMVC; m_video_codec_name = "omx-mvc"; if (hints.stereo_mode == "mono") @@ -78910,10 +51654,10 @@ index 9426604f6460651f54cc035476e69530b2ea8493..cc929b599125a44ac128713fd4331782 }; -From 0a3a48ddcd0cbcd263105f844d27afa720da9bf2 Mon Sep 17 00:00:00 2001 +From e687fbce1615c87f03cb02f73482e4eda9a0f669 Mon Sep 17 00:00:00 2001 From: Anton Fedchin <anightik@gmail.com> Date: Thu, 10 Mar 2016 18:11:33 +0300 -Subject: [PATCH 53/67] fixup! Revert supporting crappy tab/sbs subtitles. this +Subject: [PATCH 51/61] fixup! Revert supporting crappy tab/sbs subtitles. this fixes regular subtitles. --- @@ -78958,10 +51702,10 @@ index 3a080d06c90b0762482816928642e6de7810b539..7c0b70777556ac7694e7fc511cd4bb18 } -From 49a3522fd02f0d6e4adb10ec413df1bf5e181421 Mon Sep 17 00:00:00 2001 +From 677c4dc68110455444a13ab76dae151fc4f0fc85 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Tue, 10 Feb 2015 15:29:16 +0000 -Subject: [PATCH 54/67] [libcec] Add repeating keypress patch from popcornmix' +Subject: [PATCH 52/61] [libcec] Add repeating keypress patch from popcornmix' repo --- @@ -79848,10 +52592,10 @@ index 0000000000000000000000000000000000000000..8366a696562a934144cc9a21ea6f2cab +1.9.1 + -From fcfb4a5068565c3ca935cf16932f6f45f34a33d0 Mon Sep 17 00:00:00 2001 +From 75ca9806598f9ea98b1e872f68cd8dc899e9ec74 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Sat, 19 Mar 2016 17:15:29 +0000 -Subject: [PATCH 55/67] cec: hack: pretend bump to 3.1.0 +Subject: [PATCH 53/61] cec: hack: pretend bump to 3.1.0 --- tools/depends/target/libcec/Makefile | 1 + @@ -79899,32 +52643,23 @@ index 0000000000000000000000000000000000000000..9e55e51068e7befd9d4ff003156ce1ff + # cec-client + add_subdirectory(src/cec-client) -From 5dc7976451fc1ab8c7aeac2d9b4090a71e5a857d Mon Sep 17 00:00:00 2001 +From 1ca2f1145a8b3baeaee694ce8bd83e76be117cc7 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Tue, 28 Oct 2014 00:19:40 +0000 -Subject: [PATCH 56/67] [cec] Add settings for configuring button repeats +Subject: [PATCH 54/61] [cec] Add settings for configuring button repeats --- - addons/resource.language.en_gb/resources/strings.po | 17 +++++++++++++++-- + addons/resource.language.en_gb/resources/strings.po | 15 +++++++++++++++ system/peripherals.xml | 4 +++- xbmc/peripherals/devices/PeripheralCecAdapter.cpp | 16 ++++++++++++++++ - 3 files changed, 34 insertions(+), 3 deletions(-) + 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po -index 8cb9f8503c29c54cd0cb55018f867a45248c649f..a4c4387b0a78e4dc9ed875e72c4ce72dd2741fe2 100644 +index b5ae4dc1a6b21ba96fd3498baff1b63004fa6902..cb886deeceb95df1706a1176619944911d5bb64a 100644 --- a/addons/resource.language.en_gb/resources/strings.po +++ b/addons/resource.language.en_gb/resources/strings.po -@@ -19392,8 +19392,6 @@ msgctxt "#38111" - msgid "This category contains other settings for the GUI interface" - msgstr "" - --#empty strings from id 38112 to 38999 -- - #: system/settings/settings.xml - msgctxt "#39000" - msgid "HD and up" -@@ -19414,6 +19412,21 @@ msgctxt "#39003" - msgid "Accelerate h264" +@@ -19480,6 +19480,21 @@ msgctxt "#39007" + msgid "This provides access to where picture sources can be added and otherwise managed." msgstr "" +#: system/peripherals.xml @@ -79946,7 +52681,7 @@ index 8cb9f8503c29c54cd0cb55018f867a45248c649f..a4c4387b0a78e4dc9ed875e72c4ce72d msgid "Extract thumbnails from video files" msgstr "" diff --git a/system/peripherals.xml b/system/peripherals.xml -index ec3c3fe39db5f2272b3a9e49b34de3a4a063aab0..c3dbae029d397ab2e6948296df64b7a6f174b2af 100644 +index b9c8e9d658cca961a4970ab33aa4d221f2435dda..43397c44833c1068c3586eb05039bbd644c93c9b 100644 --- a/system/peripherals.xml +++ b/system/peripherals.xml @@ -31,7 +31,9 @@ @@ -79961,10 +52696,10 @@ index ec3c3fe39db5f2272b3a9e49b34de3a4a063aab0..c3dbae029d397ab2e6948296df64b7a6 <peripheral vendor_product="2548:1001,2548:1002" bus="usb" name="Pulse-Eight CEC Adapter" mapTo="cec"> diff --git a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp -index f784bded97de9491d3eaaee2fb6efc86e74dd07b..8ab327c34e08a14c598b758a67384f1c6a838e6c 100644 +index e6bcbce6911a1714e129ecd5aceead94769231f4..19b3c37bc18fcab30920b12902e8c3397a69dccc 100644 --- a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp +++ b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp -@@ -1284,6 +1284,20 @@ void CPeripheralCecAdapter::SetConfigurationFromLibCEC(const CEC::libcec_configu +@@ -1287,6 +1287,20 @@ void CPeripheralCecAdapter::SetConfigurationFromLibCEC(const CEC::libcec_configu m_configuration.bSendInactiveSource = config.bSendInactiveSource; bChanged |= SetSetting("send_inactive_source", m_configuration.bSendInactiveSource == 1); @@ -79985,7 +52720,7 @@ index f784bded97de9491d3eaaee2fb6efc86e74dd07b..8ab327c34e08a14c598b758a67384f1c m_configuration.iFirmwareVersion = config.iFirmwareVersion; m_configuration.bShutdownOnStandby = config.bShutdownOnStandby; -@@ -1388,6 +1402,8 @@ void CPeripheralCecAdapter::SetConfigurationFromSettings(void) +@@ -1391,6 +1405,8 @@ void CPeripheralCecAdapter::SetConfigurationFromSettings(void) // backwards compatibility. will be removed once the next major release of libCEC is out m_configuration.iDoubleTapTimeoutMs = GetSettingInt("double_tap_timeout_ms"); #endif @@ -79995,20 +52730,20 @@ index f784bded97de9491d3eaaee2fb6efc86e74dd07b..8ab327c34e08a14c598b758a67384f1c if (GetSettingBool("pause_playback_on_deactivate")) { -From c43daf2021b96de898d3522b5248108f9d9af488 Mon Sep 17 00:00:00 2001 +From 0ad79428d9636283d7dd952363050fac2e55898e Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Mon, 3 Nov 2014 23:17:46 +0000 -Subject: [PATCH 57/67] [cec] Don't discard buttons when repeat mode is enabled +Subject: [PATCH 55/61] [cec] Don't discard buttons when repeat mode is enabled --- xbmc/peripherals/devices/PeripheralCecAdapter.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp -index 8ab327c34e08a14c598b758a67384f1c6a838e6c..8b04a37a803c2f0ff15de35a10186e3dc9c0d130 100644 +index 19b3c37bc18fcab30920b12902e8c3397a69dccc..f859f44f6d5379154317b5760d7df720f0894e0d 100644 --- a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp +++ b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp -@@ -776,7 +776,10 @@ void CPeripheralCecAdapter::PushCecKeypress(const CecButtonPress &key) +@@ -778,7 +778,10 @@ void CPeripheralCecAdapter::PushCecKeypress(const CecButtonPress &key) CLog::Log(LOGDEBUG, "%s - received key %2x duration %d", __FUNCTION__, key.iButton, key.iDuration); CSingleLock lock(m_critSection); @@ -80021,20 +52756,20 @@ index 8ab327c34e08a14c598b758a67384f1c6a838e6c..8b04a37a803c2f0ff15de35a10186e3d if (m_currentButton.iButton == key.iButton && m_currentButton.iDuration == 0) { -From 8e198d48296f237f20faa59de880eaef75752459 Mon Sep 17 00:00:00 2001 +From 93c60a7a5fd00d2672b098dbad4a6eab8d2fc8be Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Tue, 4 Nov 2014 18:50:00 +0000 -Subject: [PATCH 58/67] [cec] Temp - more logging +Subject: [PATCH 56/61] [cec] Temp - more logging --- xbmc/peripherals/devices/PeripheralCecAdapter.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp -index 8b04a37a803c2f0ff15de35a10186e3dc9c0d130..259649721512e744fd89bfe66af6bc6324c82653 100644 +index f859f44f6d5379154317b5760d7df720f0894e0d..f1c3a6d242183507c4ce9ebf4651b0c0f7e9c5c9 100644 --- a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp +++ b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp -@@ -773,12 +773,15 @@ void CPeripheralCecAdapter::GetNextKey(void) +@@ -775,12 +775,15 @@ void CPeripheralCecAdapter::GetNextKey(void) void CPeripheralCecAdapter::PushCecKeypress(const CecButtonPress &key) { @@ -80051,7 +52786,7 @@ index 8b04a37a803c2f0ff15de35a10186e3dc9c0d130..259649721512e744fd89bfe66af6bc63 if (m_configuration.iButtonRepeatRateMs == 0 && key.iDuration > 0) { if (m_currentButton.iButton == key.iButton && m_currentButton.iDuration == 0) -@@ -787,6 +790,7 @@ void CPeripheralCecAdapter::PushCecKeypress(const CecButtonPress &key) +@@ -789,6 +792,7 @@ void CPeripheralCecAdapter::PushCecKeypress(const CecButtonPress &key) if (m_bHasButton) m_currentButton.iDuration = key.iDuration; // ignore this one, since it's already been handled by xbmc @@ -80059,7 +52794,7 @@ index 8b04a37a803c2f0ff15de35a10186e3dc9c0d130..259649721512e744fd89bfe66af6bc63 return; } // if we received a keypress with a duration set, try to find the same one without a duration set, and replace it -@@ -797,6 +801,7 @@ void CPeripheralCecAdapter::PushCecKeypress(const CecButtonPress &key) +@@ -799,6 +803,7 @@ void CPeripheralCecAdapter::PushCecKeypress(const CecButtonPress &key) if ((*it).iDuration == 0) { // replace this entry @@ -80067,7 +52802,7 @@ index 8b04a37a803c2f0ff15de35a10186e3dc9c0d130..259649721512e744fd89bfe66af6bc63 (*it).iDuration = key.iDuration; return; } -@@ -806,6 +811,7 @@ void CPeripheralCecAdapter::PushCecKeypress(const CecButtonPress &key) +@@ -808,6 +813,7 @@ void CPeripheralCecAdapter::PushCecKeypress(const CecButtonPress &key) } } @@ -80076,10 +52811,10 @@ index 8b04a37a803c2f0ff15de35a10186e3dc9c0d130..259649721512e744fd89bfe66af6bc63 } -From d61469373a92dbcb58bc8e38fc8d921106f61943 Mon Sep 17 00:00:00 2001 +From 8bc97ca506489e1f77baf7a4b978971caac9d42c Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Fri, 22 Jan 2016 12:29:41 +0000 -Subject: [PATCH 59/67] [cec] Update for libcec 3.1.0 +Subject: [PATCH 57/61] [cec] Update for libcec 3.1.0 --- configure.ac | 4 ++-- @@ -80087,7 +52822,7 @@ Subject: [PATCH 59/67] [cec] Update for libcec 3.1.0 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac -index d498f958b83813cbf5fce0a86bf07743665b5ed4..277c97f72b20650ba6a594e6363b9a863e0310a8 100644 +index 5b8c04b246ac91b0a9cf7d11659ac9726c1a80ed..5c99e8288d925c6f7499ea969783c2d6f1d3aba5 100644 --- a/configure.ac +++ b/configure.ac @@ -1433,9 +1433,9 @@ if test "x$use_libcec" != "xno"; then @@ -80103,7 +52838,7 @@ index d498f958b83813cbf5fce0a86bf07743665b5ed4..277c97f72b20650ba6a594e6363b9a86 if test "x$use_libcec" != "xno"; then diff --git a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp -index 259649721512e744fd89bfe66af6bc6324c82653..ae7fd02ea17cb11318083f853d6b1641af4ecadb 100644 +index f1c3a6d242183507c4ce9ebf4651b0c0f7e9c5c9..28a6a8148810da940f977976a627018c59a719db 100644 --- a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp +++ b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp @@ -43,7 +43,7 @@ using namespace PERIPHERALS; @@ -80115,7 +52850,7 @@ index 259649721512e744fd89bfe66af6bc6324c82653..ae7fd02ea17cb11318083f853d6b1641 /* time in seconds to ignore standby commands from devices after the screensaver has been activated */ #define SCREENSAVER_TIMEOUT 20 -@@ -1326,7 +1326,7 @@ void CPeripheralCecAdapter::SetConfigurationFromLibCEC(const CEC::libcec_configu +@@ -1329,7 +1329,7 @@ void CPeripheralCecAdapter::SetConfigurationFromLibCEC(const CEC::libcec_configu void CPeripheralCecAdapter::SetConfigurationFromSettings(void) { // client version matches the version of libCEC that we originally used the API from @@ -80125,10 +52860,10 @@ index 259649721512e744fd89bfe66af6bc6324c82653..ae7fd02ea17cb11318083f853d6b1641 // device name 'XBMC' snprintf(m_configuration.strDeviceName, 13, "%s", GetSettingString("device_name").c_str()); -From f50610a41e776cb15acbb2740587cf65b47811d0 Mon Sep 17 00:00:00 2001 +From 333e05a9c5e21d95f09b32858a6c5587e2d9beed Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Sat, 19 Mar 2016 14:46:41 +0000 -Subject: [PATCH 60/67] libcec: use system audio mode request instead of power +Subject: [PATCH 58/61] libcec: use system audio mode request instead of power on to start AVR reliable --- @@ -80194,10 +52929,10 @@ index 39ba882d0c7e270b4d1d1d566027cbaffb76b587..4565dc9f6fc0b3e6b49133443c19e107 $(LIBDYLIB): $(PLATFORM) -From b3074634af438e1dd9de238718364d82d4ee46e2 Mon Sep 17 00:00:00 2001 +From a9f40d9bf8aae676de620b2cd934ddbc1d202974 Mon Sep 17 00:00:00 2001 From: Rainer Hochecker <fernetmenta@online.de> Date: Tue, 22 Mar 2016 09:51:52 +0100 -Subject: [PATCH 61/67] python: use kodi provided cert if available +Subject: [PATCH 59/61] python: use kodi provided cert if available --- xbmc/interfaces/python/XBPython.cpp | 7 +++++-- @@ -80223,10 +52958,10 @@ index d762bf4f8fdca2a1081026089977ae8987c88b66..ff4ed7db26845905108ea0ae504e4f58 if (PyEval_ThreadsInitialized()) -From bd545157e573f1904ac552693524a4bce8789c5d Mon Sep 17 00:00:00 2001 +From 1dc7050d2ea538674cf19aadf23718e1d392560f Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Wed, 25 May 2016 18:31:17 +0100 -Subject: [PATCH 62/67] rbp: Hard code the number of buffers to improve audio +Subject: [PATCH 60/61] rbp: Hard code the number of buffers to improve audio sync --- @@ -80235,7 +52970,7 @@ Subject: [PATCH 62/67] rbp: Hard code the number of buffers to improve audio 2 files changed, 10 insertions(+) diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml -index 2e6c903df5e4d2cd064466db0ef55deada5cdc80..29d8f92c123875a83eae4832c1f6246a6deefc3c 100644 +index b7770ebc1b9568f9fe141d90a118b87106c86735..507dd61a464510760112a009d73bdc63cab19e4b 100644 --- a/system/settings/rbp.xml +++ b/system/settings/rbp.xml @@ -92,6 +92,12 @@ @@ -80252,10 +52987,10 @@ index 2e6c903df5e4d2cd064466db0ef55deada5cdc80..29d8f92c123875a83eae4832c1f6246a <category id="audio"> <group id="1"> diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp -index db537d33a5d55fc856bbd3ec0a7846df3bb060be..ee34c0b31da3b05fabae5e47ad51db2f09e682c3 100644 +index f2a133e1ff7b440ebc741878ccf87e6da090aa8c..e577d03b8280285567af0d332bc2284f6ffbf71a 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp +++ b/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp -@@ -1066,7 +1066,11 @@ void CRenderManager::UpdateDisplayLatency() +@@ -1062,7 +1062,11 @@ void CRenderManager::UpdateDisplayLatency() refresh = 0; // No idea about refresh rate when windowed, just get the default latency m_displayLatency = (double) g_advancedSettings.GetDisplayLatency(refresh); @@ -80268,347 +53003,70 @@ index db537d33a5d55fc856bbd3ec0a7846df3bb060be..ee34c0b31da3b05fabae5e47ad51db2f } -From cb6cdf5bf5a392fffc7e58631a4767ab8836ea02 Mon Sep 17 00:00:00 2001 +From c60cda47009f0431a2f2dc1764882d8b1e5e7acd Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> -Date: Wed, 8 Jun 2016 01:11:26 +0100 -Subject: [PATCH 63/67] omxvideo: Remove call to AutoInterlaceMethod. Treat - auto as advanced +Date: Mon, 4 Jul 2016 18:30:03 +0100 +Subject: [PATCH 61/61] rbp: Update the GL libs to new naming scheme +As the opensource mesa GL library is getting more usable, the name collision wih the firmware GL driver is causing issues. +As such we are renaming the firmware GL driver to avoid this. + +The new names are libbrcmEGL.so and libbrcmGLESv2.so. Both will be supported for some time, but the original name +will be dropped at some point --- - xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp | 2 +- - xbmc/cores/omxplayer/OMXVideo.cpp | 5 ++++- - 2 files changed, 5 insertions(+), 2 deletions(-) + configure.ac | 2 +- + project/cmake/modules/FindOpenGLES.cmake | 6 +++--- + tools/depends/configure.ac | 2 +- + 3 files changed, 5 insertions(+), 5 deletions(-) -diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp -index d65857779628debfc85b47b8dd283513edb5a319..523e52c27de2711ca03c6b06767c940be6e3d177 100644 ---- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp -+++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp -@@ -632,7 +632,7 @@ bool CMMALRenderer::Supports(ESCALINGMETHOD method) +diff --git a/configure.ac b/configure.ac +index 5c99e8288d925c6f7499ea969783c2d6f1d3aba5..54b9552f8ee5c2dc8bace2337a0254b5e5191fee 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -929,7 +929,7 @@ if test "$use_gles" = "yes"; then + AC_DEFINE([HAVE_LIBEGL],[1],["Define to 1 if you have the `EGL' library (-lEGL)."]) + AC_DEFINE([HAVE_LIBGLESV2],[1],["Define to 1 if you have the `GLESv2' library (-lGLESv2)."]) + AC_MSG_RESULT(== WARNING: OpenGLES support is assumed.) +- LIBS="$LIBS -lEGL -lGLESv2 -lbcm_host -lvcos -lvchiq_arm -lmmal -lmmal_core -lmmal_util -lvcsm" ++ LIBS="$LIBS -lbrcmEGL -lbrcmGLESv2 -lbcm_host -lvcos -lvchiq_arm -lmmal -lmmal_core -lmmal_util -lvcsm" + else + AC_CHECK_LIB([EGL], [main],, AC_MSG_ERROR($missing_library)) + AC_CHECK_LIB([GLESv2],[main],, AC_MSG_ERROR($missing_library)) +diff --git a/project/cmake/modules/FindOpenGLES.cmake b/project/cmake/modules/FindOpenGLES.cmake +index 5d71dd4ad34de4d4bb3a4f24198c86c82ebca2d4..4c1cba7a85c32140e9ebf4c766e845b2e97f769a 100644 +--- a/project/cmake/modules/FindOpenGLES.cmake ++++ b/project/cmake/modules/FindOpenGLES.cmake +@@ -13,7 +13,7 @@ + find_package(EMBEDDED) - EINTERLACEMETHOD CMMALRenderer::AutoInterlaceMethod() - { -- return m_sourceWidth * m_sourceHeight <= 576 * 720 ? VS_INTERLACEMETHOD_MMAL_ADVANCED : VS_INTERLACEMETHOD_MMAL_BOB; -+ return VS_INTERLACEMETHOD_MMAL_ADVANCED; - } + if(PKG_CONFIG_FOUND AND NOT PLATFORM STREQUAL "raspberry-pi") +- pkg_check_modules(PC_OPENGLES glesv2) ++ pkg_check_modules(PC_OPENGLES brcmglesv2) + if(NOT OPENGLES_FOUND AND EMBEDDED_FOUND) + set(CMAKE_PREFIX_PATH ${EMBEDDED_FOUND} ${CMAKE_PREFIX_PATH}) + endif() +@@ -22,9 +22,9 @@ endif() + if(NOT CORE_SYSTEM_NAME STREQUAL ios) + find_path(OPENGLES_INCLUDE_DIR GLES2/gl2.h + PATHS ${PC_OPENGLES_INCLUDEDIR}) +- find_library(OPENGLES_gl_LIBRARY NAMES GLESv2 ++ find_library(OPENGLES_gl_LIBRARY NAMES brcmGLESv2 + PATHS ${PC_OPENGLES_LIBDIR}) +- find_library(OPENGLES_egl_LIBRARY NAMES EGL ++ find_library(OPENGLES_egl_LIBRARY NAMES brcmEGL + PATHS ${PC_OPENGLES_LIBDIR}) + else() + find_library(OPENGLES_gl_LIBRARY NAMES OpenGLES +diff --git a/tools/depends/configure.ac b/tools/depends/configure.ac +index fb0bd6dad18199e8893c38644f93659bf0a3f61b..010288dc5de74380fc3795d00dbd99847cf2ed3e 100644 +--- a/tools/depends/configure.ac ++++ b/tools/depends/configure.ac +@@ -390,7 +390,7 @@ if test "$target_platform" = "raspberry-pi" ; then + -isystem${use_firmware}/opt/vc/include \ + -isystem${use_firmware}/opt/vc/include/interface/vcos/pthreads \ + -isystem${use_firmware}/opt/vc/include/interface/vmcs_host/linux" +- platform_ldflags+=" -L${use_firmware}/opt/vc/lib -lEGL -lGLESv2 -lbcm_host -lvcos \ ++ platform_ldflags+=" -L${use_firmware}/opt/vc/lib -lbrcmEGL -lbrcmGLESv2 -lbcm_host -lvcos \ + -lvchiq_arm" + fi - void CMMALRenderer::SetVideoRect(const CRect& InSrcRect, const CRect& InDestRect) -diff --git a/xbmc/cores/omxplayer/OMXVideo.cpp b/xbmc/cores/omxplayer/OMXVideo.cpp -index de15bfff05d23949d6e6f4304b15aa7d79120dc2..79685835382422d0a22d7b75d7c1408e2c053403 100644 ---- a/xbmc/cores/omxplayer/OMXVideo.cpp -+++ b/xbmc/cores/omxplayer/OMXVideo.cpp -@@ -242,7 +242,10 @@ bool COMXVideo::PortSettingsChanged(ResolutionUpdateInfo &resinfo) - - if(m_deinterlace) - { -- EINTERLACEMETHOD interlace_method = m_renderManager.AutoInterlaceMethod(CMediaSettings::GetInstance().GetCurrentVideoSettings().m_InterlaceMethod); -+ EINTERLACEMETHOD interlace_method = CMediaSettings::GetInstance().GetCurrentVideoSettings().m_InterlaceMethod; -+ if (interlace_method == VS_INTERLACEMETHOD_AUTO) -+ interlace_method = VS_INTERLACEMETHOD_MMAL_ADVANCED; -+ - bool advanced_deinterlace = interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED || interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED_HALF; - bool half_framerate = interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED_HALF || interlace_method == VS_INTERLACEMETHOD_MMAL_BOB_HALF; - - -From 120051ba33cc7dc2885b3bf3abf49c4903bee0f8 Mon Sep 17 00:00:00 2001 -From: popcornmix <popcornmix@gmail.com> -Date: Wed, 15 Jun 2016 23:41:43 +0100 -Subject: [PATCH 64/67] mmal_codec: Use EOS through codec to determine drain is - complete - -Rather than relying on a timeout from codec, feed an EOS through to ensure all frames have been returned ---- - .../VideoPlayer/DVDCodecs/Video/MMALCodec.cpp | 72 ++++++++++++++-------- - xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.h | 3 + - 2 files changed, 49 insertions(+), 26 deletions(-) - -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -index 470083b2256d23488ca476cebfe8d3ef9f62377e..cd0d30d77cc1cd8803ccde317bcc2f3cd61000e4 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -@@ -117,6 +117,9 @@ CMMALVideo::CMMALVideo(CProcessInfo &processInfo) : CDVDVideoCodec(processInfo) - m_fps = 0.0f; - m_num_decoded = 0; - m_codecControlFlags = 0; -+ m_got_eos = false; -+ m_packet_num = 0; -+ m_packet_num_eos = ~0; - } - - CMMALVideo::~CMMALVideo() -@@ -243,7 +246,7 @@ void CMMALVideo::dec_output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf - { - if (!(buffer->cmd == 0 && buffer->length > 0)) - if (g_advancedSettings.CanLogComponent(LOGVIDEO)) -- CLog::Log(LOGDEBUG, "%s::%s port:%p buffer %p, len %d cmd:%x", CLASSNAME, __func__, port, buffer, buffer->length, buffer->cmd); -+ CLog::Log(LOGDEBUG, "%s::%s port:%p buffer %p, len %d cmd:%x flags:%x", CLASSNAME, __func__, port, buffer, buffer->length, buffer->cmd, buffer->flags); - - bool kept = false; - -@@ -288,6 +291,12 @@ void CMMALVideo::dec_output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf - kept = true; - } - } -+ if (buffer->flags & MMAL_BUFFER_HEADER_FLAG_EOS) -+ { -+ CSingleLock lock(m_output_mutex); -+ m_got_eos = true; -+ m_output_cond.notifyAll(); -+ } - } - else if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED) - { -@@ -790,11 +799,18 @@ int CMMALVideo::Decode(uint8_t* pData, int iSize, double dts, double pts) - - MMAL_BUFFER_HEADER_T *buffer; - MMAL_STATUS_T status; -- -+ bool drain = (m_codecControlFlags & DVD_CODEC_CTRL_DRAIN) ? true : false; -+ bool send_eos = drain && !m_got_eos && m_packet_num_eos != m_packet_num; -+ // we don't get an EOS response if no packets have been sent -+ if (m_packet_num == 0) -+ { -+ send_eos = false; -+ m_got_eos = true; -+ } - Prime(); - while (1) - { -- if (pData) -+ if (pData || send_eos) - { - // 500ms timeout - { -@@ -817,17 +833,25 @@ int CMMALVideo::Decode(uint8_t* pData, int iSize, double dts, double pts) - if (m_dropState) - buffer->flags |= MMAL_BUFFER_HEADER_FLAG_USER3; - -- memcpy(buffer->data, pData, buffer->length); -+ if (pData) -+ memcpy(buffer->data, pData, buffer->length); - iSize -= buffer->length; - pData += buffer->length; - - if (iSize == 0) -+ { -+ m_packet_num++; - buffer->flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_END; -- -+ if (send_eos) -+ { -+ buffer->flags |= MMAL_BUFFER_HEADER_FLAG_EOS; -+ m_packet_num_eos = m_packet_num; -+ m_got_eos = false; -+ } -+ } - if (g_advancedSettings.CanLogComponent(LOGVIDEO)) - CLog::Log(LOGDEBUG, "%s::%s - %-8p %-6d/%-6d dts:%.3f pts:%.3f flags:%x ready_queue(%d)", - CLASSNAME, __func__, buffer, buffer->length, iSize, dts == DVD_NOPTS_VALUE ? 0.0 : dts*1e-6, pts == DVD_NOPTS_VALUE ? 0.0 : pts*1e-6, buffer->flags, m_output_ready.size()); -- assert((int)buffer->length > 0); - status = mmal_port_send_buffer(m_dec_input, buffer); - if (status != MMAL_SUCCESS) - { -@@ -879,36 +903,28 @@ int CMMALVideo::Decode(uint8_t* pData, int iSize, double dts, double pts) - bool full = queued > DVD_MSEC_TO_TIME(1000); - int ret = 0; - -- unsigned int pics = m_output_ready.size(); -- if (m_preroll && (pics >= GetAllowedReferences() || m_codecControlFlags & DVD_CODEC_CTRL_DRAIN)) -- m_preroll = false; -- if (pics > 0 && !m_preroll) -- ret |= VC_PICTURE; -- if ((m_preroll || pics <= 1) && mmal_queue_length(m_dec_input_pool->queue) > 0 && !(m_codecControlFlags & DVD_CODEC_CTRL_DRAIN)) -- ret |= VC_BUFFER; -- -- bool slept = false; -- if (!ret) -+ XbmcThreads::EndTime delay(500); -+ while (!ret && !delay.IsTimePast()) - { -- slept = true; -+ unsigned int pics = m_output_ready.size(); -+ if (m_preroll && (pics >= GetAllowedReferences() || drain)) -+ m_preroll = false; -+ if (pics > 0 && !m_preroll) -+ ret |= VC_PICTURE; -+ if ((m_preroll || pics <= 1) && mmal_queue_length(m_dec_input_pool->queue) > 0 && (!drain || m_got_eos || m_packet_num_eos != m_packet_num)) -+ ret |= VC_BUFFER; -+ if (!ret) - { - // otherwise we busy spin - lock.Leave(); - CSingleLock output_lock(m_output_mutex); -- m_output_cond.wait(output_lock, 30); -+ m_output_cond.wait(output_lock, delay.MillisLeft()); - lock.Enter(); - } -- unsigned int pics = m_output_ready.size(); -- if (m_preroll && (pics >= GetAllowedReferences() || m_codecControlFlags & DVD_CODEC_CTRL_DRAIN)) -- m_preroll = false; -- if (pics > 0 && !m_preroll) -- ret |= VC_PICTURE; -- if ((m_preroll || pics <= 1) && (mmal_queue_length(m_dec_input_pool->queue) > 0 || m_codecControlFlags & DVD_CODEC_CTRL_DRAIN)) -- ret |= VC_BUFFER; - } - - if (g_advancedSettings.CanLogComponent(LOGVIDEO)) -- CLog::Log(LOGDEBUG, "%s::%s - ret(%x) pics(%d) inputs(%d) slept(%d) queued(%.2f) (%.2f:%.2f) full(%d) flags(%x) preroll(%d)", CLASSNAME, __func__, ret, m_output_ready.size(), mmal_queue_length(m_dec_input_pool->queue), slept, queued*1e-6, m_demuxerPts*1e-6, m_decoderPts*1e-6, full, m_codecControlFlags, m_preroll); -+ CLog::Log(LOGDEBUG, "%s::%s - ret(%x) pics(%d) inputs(%d) slept(%2d) queued(%.2f) (%.2f:%.2f) full(%d) flags(%x) preroll(%d) eos(%d %d/%d)", CLASSNAME, __func__, ret, m_output_ready.size(), mmal_queue_length(m_dec_input_pool->queue), 500-delay.MillisLeft(), queued*1e-6, m_demuxerPts*1e-6, m_decoderPts*1e-6, full, m_codecControlFlags, m_preroll, m_got_eos, m_packet_num, m_packet_num_eos); - - return ret; - } -@@ -981,6 +997,10 @@ void CMMALVideo::Reset(void) - m_demuxerPts = DVD_NOPTS_VALUE; - m_codecControlFlags = 0; - m_dropState = false; -+ m_num_decoded = 0; -+ m_got_eos = false; -+ m_packet_num = 0; -+ m_packet_num_eos = ~0; - m_preroll = !m_hints.stills && (m_speed == DVD_PLAYSPEED_NORMAL || m_speed == DVD_PLAYSPEED_PAUSE); - } - -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.h -index d008c6c538819a05be9925ab8cd342b131e511d8..122a5e24f5ffb1bf2415867ec98d8e5104339ab1 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.h -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.h -@@ -134,6 +134,9 @@ protected: - int m_codecControlFlags; - bool m_dropState; - bool m_preroll; -+ bool m_got_eos; -+ uint32_t m_packet_num; -+ uint32_t m_packet_num_eos; - - CCriticalSection m_sharedSection; - MMAL_COMPONENT_T *m_dec; - -From d91a21ae571cc2bf2c5103c8c72fc1262379f4b5 Mon Sep 17 00:00:00 2001 -From: popcornmix <popcornmix@gmail.com> -Date: Fri, 17 Jun 2016 16:23:25 +0100 -Subject: [PATCH 65/67] rbp: Update transposed video scaling to match other - platforms - ---- - .../VideoRenderers/HwDecRender/MMALRenderer.cpp | 29 ++++++++++++++++++---- - xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 29 ++++++++++++++++++---- - 2 files changed, 48 insertions(+), 10 deletions(-) - -diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp -index 523e52c27de2711ca03c6b06767c940be6e3d177..8a4bf24625a57b11908f4f38588fb348581556a6 100644 ---- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp -+++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp -@@ -656,11 +656,30 @@ void CMMALRenderer::SetVideoRect(const CRect& InSrcRect, const CRect& InDestRect - // fix up transposed video - if (m_renderOrientation == 90 || m_renderOrientation == 270) - { -- float diff = (DestRect.Height() - DestRect.Width()) * 0.5f; -- DestRect.x1 -= diff; -- DestRect.x2 += diff; -- DestRect.y1 += diff; -- DestRect.y2 -= diff; -+ float newWidth, newHeight; -+ float aspectRatio = GetAspectRatio(); -+ // clamp width if too wide -+ if (DestRect.Height() > DestRect.Width()) -+ { -+ newWidth = DestRect.Width(); // clamp to the width of the old dest rect -+ newHeight = newWidth * aspectRatio; -+ } -+ else // else clamp to height -+ { -+ newHeight = DestRect.Height(); // clamp to the height of the old dest rect -+ newWidth = newHeight / aspectRatio; -+ } -+ -+ // calculate the center point of the view and offsets -+ float centerX = DestRect.x1 + DestRect.Width() * 0.5f; -+ float centerY = DestRect.y1 + DestRect.Height() * 0.5f; -+ float diffX = newWidth * 0.5f; -+ float diffY = newHeight * 0.5f; -+ -+ DestRect.x1 = centerX - diffX; -+ DestRect.x2 = centerX + diffX; -+ DestRect.y1 = centerY - diffY; -+ DestRect.y2 = centerY + diffY; - } - - // check if destination rect or video view mode has changed -diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -index d61dc4f2668f8aca91bce79cfb631034061c491c..ed138297b49c8d3e6b42a1f1fa5fa08bd01be11b 100644 ---- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -@@ -640,11 +640,30 @@ void OMXPlayerVideo::SetVideoRect(const CRect &InSrcRect, const CRect &InDestRec - // fix up transposed video - if (m_hints.orientation == 90 || m_hints.orientation == 270) - { -- float diff = (DestRect.Height() - DestRect.Width()) * 0.5f; -- DestRect.x1 -= diff; -- DestRect.x2 += diff; -- DestRect.y1 += diff; -- DestRect.y2 -= diff; -+ float newWidth, newHeight; -+ float aspectRatio = GetAspectRatio(); -+ // clamp width if too wide -+ if (DestRect.Height() > DestRect.Width()) -+ { -+ newWidth = DestRect.Width(); // clamp to the width of the old dest rect -+ newHeight = newWidth * aspectRatio; -+ } -+ else // else clamp to height -+ { -+ newHeight = DestRect.Height(); // clamp to the height of the old dest rect -+ newWidth = newHeight / aspectRatio; -+ } -+ -+ // calculate the center point of the view and offsets -+ float centerX = DestRect.x1 + DestRect.Width() * 0.5f; -+ float centerY = DestRect.y1 + DestRect.Height() * 0.5f; -+ float diffX = newWidth * 0.5f; -+ float diffY = newHeight * 0.5f; -+ -+ DestRect.x1 = centerX - diffX; -+ DestRect.x2 = centerX + diffX; -+ DestRect.y1 = centerY - diffY; -+ DestRect.y2 = centerY + diffY; - } - - // check if destination rect or video view mode has changed - -From bd128ae3789c33616ae6ebd55fbae13984f98477 Mon Sep 17 00:00:00 2001 -From: popcornmix <popcornmix@gmail.com> -Date: Sun, 19 Jun 2016 16:53:49 +0100 -Subject: [PATCH 66/67] mmalcodec: Add another buffer when deinterlacing - -See: http://forum.kodi.tv/showthread.php?tid=276372 ---- - xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -index cd0d30d77cc1cd8803ccde317bcc2f3cd61000e4..6fd59a64dd48c05d1ccc3183adc5deda16e930a2 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -@@ -400,7 +400,7 @@ bool CMMALVideo::CreateDeinterlace(EINTERLACEMETHOD interlace_method) - m_deint_input->userdata = (struct MMAL_PORT_USERDATA_T *)this; - - // Image_fx assumed 3 frames of context. simple deinterlace doesn't require this -- status = mmal_port_parameter_set_uint32(m_deint_input, MMAL_PARAMETER_EXTRA_BUFFERS, GetAllowedReferences() - 5 + advanced_deinterlace ? 2:0); -+ status = mmal_port_parameter_set_uint32(m_deint_input, MMAL_PARAMETER_EXTRA_BUFFERS, 1 + GetAllowedReferences() - 5 + advanced_deinterlace ? 2:0); - if (status != MMAL_SUCCESS) - CLog::Log(LOGERROR, "%s::%s Failed to enable extra buffers on %s (status=%x %s)", CLASSNAME, __func__, m_deint_input->name, status, mmal_status_to_string(status)); - - -From a89d7094bd34a58451effaa3fbbc72651888ea23 Mon Sep 17 00:00:00 2001 -From: popcornmix <popcornmix@gmail.com> -Date: Fri, 1 Jul 2016 13:15:36 +0100 -Subject: [PATCH 67/67] UNSTABLE: This is a placeholder. Commits after this - point are considered experimental. - ---- - .placeholder | 0 - 1 file changed, 0 insertions(+), 0 deletions(-) - create mode 100644 .placeholder - -diff --git a/.placeholder b/.placeholder -new file mode 100644 -index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/projects/RPi2/patches/kodi/kodi-000-backports.patch b/projects/RPi2/patches/kodi/kodi-000-backports.patch deleted file mode 100644 index e09ca0ff94..0000000000 --- a/projects/RPi2/patches/kodi/kodi-000-backports.patch +++ /dev/null @@ -1,2187 +0,0 @@ -From 618094ed6ad5b01165de2111410dafbe4160598c Mon Sep 17 00:00:00 2001 -From: Rainer Hochecker <fernetmenta@online.de> -Date: Tue, 31 May 2016 13:28:48 +0200 -Subject: [PATCH 1/3] VideoPlayer: expose stream player info to GUI - ---- - xbmc/GUIInfoManager.cpp | 60 +++++++ - xbmc/cores/DataCacheCore.cpp | 166 ++++++++++++++++- - xbmc/cores/DataCacheCore.h | 55 +++++- - .../VideoPlayer/DVDCodecs/Audio/DVDAudioCodec.h | 6 +- - .../DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp | 3 +- - .../DVDCodecs/Audio/DVDAudioCodecFFmpeg.h | 4 +- - .../DVDCodecs/Audio/DVDAudioCodecPassthrough.cpp | 9 +- - .../DVDCodecs/Audio/DVDAudioCodecPassthrough.h | 4 +- - .../VideoPlayer/DVDCodecs/DVDFactoryCodec.cpp | 6 +- - xbmc/cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.h | 3 +- - .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 30 +++- - .../DVDCodecs/Video/DVDVideoCodecFFmpeg.h | 1 + - xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp | 6 +- - xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.h | 5 +- - xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp | 19 +- - xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.h | 5 +- - xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.cpp | 4 +- - xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.h | 6 +- - xbmc/cores/VideoPlayer/DVDCodecs/Video/VTB.cpp | 4 +- - xbmc/cores/VideoPlayer/DVDCodecs/Video/VTB.h | 6 +- - xbmc/cores/VideoPlayer/Process/ProcessInfo.cpp | 199 +++++++++++++++++++++ - xbmc/cores/VideoPlayer/Process/ProcessInfo.h | 47 +++++ - xbmc/cores/VideoPlayer/VideoPlayerAudio.cpp | 11 +- - xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp | 5 + - xbmc/cores/omxplayer/OMXPlayerAudio.cpp | 1 + - xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 7 + - xbmc/cores/paplayer/VideoPlayerCodec.cpp | 4 +- - xbmc/cores/paplayer/VideoPlayerCodec.h | 2 + - xbmc/guiinfo/GUIInfoLabels.h | 14 ++ - 29 files changed, 662 insertions(+), 30 deletions(-) - -diff --git a/xbmc/GUIInfoManager.cpp b/xbmc/GUIInfoManager.cpp -index 0d37f1f..ab5cb12 100644 ---- a/xbmc/GUIInfoManager.cpp -+++ b/xbmc/GUIInfoManager.cpp -@@ -2108,6 +2108,22 @@ const infomap videoplayer[] = {{ "title", VIDEOPLAYER_TITLE }, - { "episodename", VIDEOPLAYER_EPISODENAME } - }; - -+const infomap player_process[] = -+{ -+ { "videodecoder", PLAYER_PROCESS_VIDEODECODER }, -+ { "deintmethod", PLAYER_PROCESS_DEINTMETHOD }, -+ { "pixformat", PLAYER_PROCESS_PIXELFORMAT }, -+ { "videowidth", PLAYER_PROCESS_VIDEOWIDTH }, -+ { "videoheight", PLAYER_PROCESS_VIDEOHEIGHT }, -+ { "videofps", PLAYER_PROCESS_VIDEOFPS }, -+ { "videodar", PLAYER_PROCESS_VIDEODAR }, -+ { "videohwdecoder", PLAYER_PROCESS_VIDEOHWDECODER }, -+ { "audiodecoder", PLAYER_PROCESS_AUDIODECODER }, -+ { "audiochannels", PLAYER_PROCESS_AUDIOCHANNELS }, -+ { "audiosamplerate", PLAYER_PROCESS_AUDIOSAMPLERATE }, -+ { "audiobitspersample", PLAYER_PROCESS_AUDIOBITSPERSAMPLE } -+}; -+ - /// \page modules__General__List_of_gui_access - /// \section modules__General__List_of_gui_access_Container Container - /// @{ -@@ -5320,6 +5336,14 @@ int CGUIInfoManager::TranslateSingleString(const std::string &strCondition, bool - return videoplayer[i].val; - } - } -+ else if (cat.name == "player_process") -+ { -+ for (size_t i = 0; i < sizeof(player_process) / sizeof(infomap); i++) -+ { -+ if (prop.name == player_process[i].str) -+ return videoplayer[i].val; -+ } -+ } - else if (cat.name == "slideshow") - { - for (size_t i = 0; i < sizeof(slideshow) / sizeof(infomap); i++) -@@ -5993,6 +6017,27 @@ std::string CGUIInfoManager::GetLabel(int info, int contextWindow, std::string * - strLabel = info.language; - } - break; -+ case PLAYER_PROCESS_VIDEODECODER: -+ strLabel = g_dataCacheCore.GetVideoDecoderName(); -+ break; -+ case PLAYER_PROCESS_DEINTMETHOD: -+ strLabel = g_dataCacheCore.GetVideoDeintMethod(); -+ break; -+ case PLAYER_PROCESS_PIXELFORMAT: -+ strLabel = g_dataCacheCore.GetVideoPixelFormat(); -+ break; -+ case PLAYER_PROCESS_VIDEOFPS: -+ strLabel = StringUtils::FormatNumber(g_dataCacheCore.GetVideoFps()); -+ break; -+ case PLAYER_PROCESS_VIDEODAR: -+ strLabel = StringUtils::FormatNumber(CServiceBroker::GetDataCacheCore().GetVideoDAR()); -+ break; -+ case PLAYER_PROCESS_AUDIODECODER: -+ strLabel = g_dataCacheCore.GetAudioDecoderName(); -+ break; -+ case PLAYER_PROCESS_AUDIOCHANNELS: -+ strLabel = g_dataCacheCore.GetAudioChannels(); -+ break; - case RDS_AUDIO_LANG: - case RDS_CHANNEL_COUNTRY: - case RDS_TITLE: -@@ -6555,6 +6600,18 @@ bool CGUIInfoManager::GetInt(int &value, int info, int contextWindow, const CGUI - case SYSTEM_BATTERY_LEVEL: - value = g_powerManager.BatteryLevel(); - return true; -+ case PLAYER_PROCESS_VIDEOWIDTH: -+ value = g_dataCacheCore.GetVideoWidth(); -+ return true; -+ case PLAYER_PROCESS_VIDEOHEIGHT: -+ value = g_dataCacheCore.GetVideoHeight(); -+ return true; -+ case PLAYER_PROCESS_AUDIOSAMPLERATE: -+ value = g_dataCacheCore.GetAudioSampleRate(); -+ return true; -+ case PLAYER_PROCESS_AUDIOBITSPERSAMPLE: -+ value = g_dataCacheCore.GetAudioBitsPerSampe(); -+ return true; - } - return false; - } -@@ -7090,6 +7147,9 @@ bool CGUIInfoManager::GetBool(int condition1, int contextWindow, const CGUIListI - !m_currentFile->GetPVRRadioRDSInfoTag()->GetSMSStudio().empty() || - !m_currentFile->GetPVRRadioRDSInfoTag()->GetPhoneStudio().empty()); - break; -+ case PLAYER_PROCESS_VIDEOHWDECODER: -+ bReturn = g_dataCacheCore.IsVideoHwDecoder(); -+ break; - default: // default, use integer value different from 0 as true - { - int val; -diff --git a/xbmc/cores/DataCacheCore.cpp b/xbmc/cores/DataCacheCore.cpp -index 68cf2fb..cbb0a4f 100644 ---- a/xbmc/cores/DataCacheCore.cpp -+++ b/xbmc/cores/DataCacheCore.cpp -@@ -19,6 +19,12 @@ - */ - - #include "cores/DataCacheCore.h" -+#include "threads/SingleLock.h" -+ -+CDataCacheCore::CDataCacheCore() -+{ -+ m_hasAVInfoChanges = false; -+} - - bool CDataCacheCore::HasAVInfoChanges() - { -@@ -35,4 +41,162 @@ void CDataCacheCore::SignalVideoInfoChange() - void CDataCacheCore::SignalAudioInfoChange() - { - m_hasAVInfoChanges = true; --} -\ No newline at end of file -+} -+ -+void CDataCacheCore::SetVideoDecoderName(std::string name, bool isHw) -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ m_playerVideoInfo.decoderName = name; -+ m_playerVideoInfo.isHwDecoder = isHw; -+} -+ -+std::string CDataCacheCore::GetVideoDecoderName() -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ return m_playerVideoInfo.decoderName; -+} -+ -+bool CDataCacheCore::IsVideoHwDecoder() -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ return m_playerVideoInfo.isHwDecoder; -+} -+ -+ -+void CDataCacheCore::SetVideoDeintMethod(std::string method) -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ m_playerVideoInfo.deintMethod = method; -+} -+ -+std::string CDataCacheCore::GetVideoDeintMethod() -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ return m_playerVideoInfo.deintMethod; -+} -+ -+void CDataCacheCore::SetVideoPixelFormat(std::string pixFormat) -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ m_playerVideoInfo.pixFormat = pixFormat; -+} -+ -+std::string CDataCacheCore::GetVideoPixelFormat() -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ return m_playerVideoInfo.pixFormat; -+} -+ -+void CDataCacheCore::SetVideoDimensions(int width, int height) -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ m_playerVideoInfo.width = width; -+ m_playerVideoInfo.height = height; -+} -+ -+int CDataCacheCore::GetVideoWidth() -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ return m_playerVideoInfo.width; -+} -+ -+int CDataCacheCore::GetVideoHeight() -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ return m_playerVideoInfo.height; -+} -+ -+void CDataCacheCore::SetVideoFps(float fps) -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ m_playerVideoInfo.fps = fps; -+} -+ -+float CDataCacheCore::GetVideoFps() -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ return m_playerVideoInfo.fps; -+} -+ -+void CDataCacheCore::SetVideoDAR(float dar) -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ m_playerVideoInfo.dar = dar; -+} -+ -+float CDataCacheCore::GetVideoDAR() -+{ -+ CSingleLock lock(m_videoPlayerSection); -+ -+ return m_playerVideoInfo.dar; -+} -+ -+// player audio info -+void CDataCacheCore::SetAudioDecoderName(std::string name) -+{ -+ CSingleLock lock(m_audioPlayerSection); -+ -+ m_playerAudioInfo.decoderName = name; -+} -+ -+std::string CDataCacheCore::GetAudioDecoderName() -+{ -+ CSingleLock lock(m_audioPlayerSection); -+ -+ return m_playerAudioInfo.decoderName; -+} -+ -+void CDataCacheCore::SetAudioChannels(std::string channels) -+{ -+ CSingleLock lock(m_audioPlayerSection); -+ -+ m_playerAudioInfo.channels = channels; -+} -+ -+std::string CDataCacheCore::GetAudioChannels() -+{ -+ CSingleLock lock(m_audioPlayerSection); -+ -+ return m_playerAudioInfo.channels; -+} -+ -+void CDataCacheCore::SetAudioSampleRate(int sampleRate) -+{ -+ CSingleLock lock(m_audioPlayerSection); -+ -+ m_playerAudioInfo.sampleRate = sampleRate; -+} -+ -+int CDataCacheCore::GetAudioSampleRate() -+{ -+ CSingleLock lock(m_audioPlayerSection); -+ -+ return m_playerAudioInfo.sampleRate; -+} -+ -+void CDataCacheCore::SetAudioBitsPerSample(int bitsPerSample) -+{ -+ CSingleLock lock(m_audioPlayerSection); -+ -+ m_playerAudioInfo.bitsPerSample = bitsPerSample; -+} -+ -+int CDataCacheCore::GetAudioBitsPerSampe() -+{ -+ CSingleLock lock(m_audioPlayerSection); -+ -+ return m_playerAudioInfo.bitsPerSample; -+} -diff --git a/xbmc/cores/DataCacheCore.h b/xbmc/cores/DataCacheCore.h -index 0df013d..e16c81f 100644 ---- a/xbmc/cores/DataCacheCore.h -+++ b/xbmc/cores/DataCacheCore.h -@@ -20,15 +20,68 @@ - * - */ - -+#include <atomic> -+#include <string> -+#include "threads/CriticalSection.h" -+ - class CDataCacheCore - { - public: -+ CDataCacheCore(); - bool HasAVInfoChanges(); - void SignalVideoInfoChange(); - void SignalAudioInfoChange(); - -+ // player video info -+ void SetVideoDecoderName(std::string name, bool isHw); -+ std::string GetVideoDecoderName(); -+ bool IsVideoHwDecoder(); -+ void SetVideoDeintMethod(std::string method); -+ std::string GetVideoDeintMethod(); -+ void SetVideoPixelFormat(std::string pixFormat); -+ std::string GetVideoPixelFormat(); -+ void SetVideoDimensions(int width, int height); -+ int GetVideoWidth(); -+ int GetVideoHeight(); -+ void SetVideoFps(float fps); -+ float GetVideoFps(); -+ void SetVideoDAR(float dar); -+ float GetVideoDAR(); -+ -+ // player audio info -+ void SetAudioDecoderName(std::string name); -+ std::string GetAudioDecoderName(); -+ void SetAudioChannels(std::string channels); -+ std::string GetAudioChannels(); -+ void SetAudioSampleRate(int sampleRate); -+ int GetAudioSampleRate(); -+ void SetAudioBitsPerSample(int bitsPerSample); -+ int GetAudioBitsPerSampe(); -+ - protected: -- volatile bool m_hasAVInfoChanges; -+ std::atomic_bool m_hasAVInfoChanges; -+ -+ CCriticalSection m_videoPlayerSection; -+ struct SPlayerVideoInfo -+ { -+ std::string decoderName; -+ bool isHwDecoder; -+ std::string deintMethod; -+ std::string pixFormat; -+ int width; -+ int height; -+ float fps; -+ float dar; -+ } m_playerVideoInfo; -+ -+ CCriticalSection m_audioPlayerSection; -+ struct SPlayerAudioInfo -+ { -+ std::string decoderName; -+ std::string channels; -+ int sampleRate; -+ int bitsPerSample; -+ } m_playerAudioInfo; - }; - - extern CDataCacheCore g_dataCacheCore; -\ No newline at end of file -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodec.h b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodec.h -index 7e0da61..bb698da 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodec.h -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodec.h -@@ -23,6 +23,7 @@ - #include "system.h" - #include "cores/AudioEngine/Utils/AEAudioFormat.h" - #include "cores/AudioEngine/Utils/AEUtil.h" -+#include "cores/VideoPlayer/Process/ProcessInfo.h" - #include "DVDClock.h" - - -@@ -64,7 +65,7 @@ class CDVDAudioCodec - { - public: - -- CDVDAudioCodec() {} -+ CDVDAudioCodec(CProcessInfo &processInfo) : m_processInfo(processInfo) {} - virtual ~CDVDAudioCodec() {} - - /* -@@ -138,4 +139,7 @@ class CDVDAudioCodec - * should return the ffmpeg profile value - */ - virtual int GetProfile() { return 0; } -+ -+protected: -+ CProcessInfo &m_processInfo; - }; -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp -index a21894e..f5880cc 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp -@@ -35,7 +35,7 @@ extern "C" { - #include "cores/AudioEngine/Utils/AEUtil.h" - #endif - --CDVDAudioCodecFFmpeg::CDVDAudioCodecFFmpeg() : CDVDAudioCodec() -+CDVDAudioCodecFFmpeg::CDVDAudioCodecFFmpeg(CProcessInfo &processInfo) : CDVDAudioCodec(processInfo) - { - m_pCodecContext = NULL; - -@@ -126,6 +126,7 @@ bool CDVDAudioCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options - m_iSampleFormat = AV_SAMPLE_FMT_NONE; - m_matrixEncoding = AV_MATRIX_ENCODING_NONE; - -+ m_processInfo.SetAudioDecoderName(m_pCodecContext->codec->name); - return true; - } - -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.h b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.h -index a15317a..d5760bb 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.h -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.h -@@ -29,10 +29,12 @@ extern "C" { - #include "libswresample/swresample.h" - } - -+class CProcessInfo; -+ - class CDVDAudioCodecFFmpeg : public CDVDAudioCodec - { - public: -- CDVDAudioCodecFFmpeg(); -+ CDVDAudioCodecFFmpeg(CProcessInfo &processInfo); - virtual ~CDVDAudioCodecFFmpeg(); - virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options); - virtual void Dispose(); -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.cpp -index 1fb00e1..8009297 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.cpp -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.cpp -@@ -29,7 +29,8 @@ - - #define TRUEHD_BUF_SIZE 61440 - --CDVDAudioCodecPassthrough::CDVDAudioCodecPassthrough(void) : -+CDVDAudioCodecPassthrough::CDVDAudioCodecPassthrough(CProcessInfo &processInfo) : -+ CDVDAudioCodec(processInfo), - m_buffer(NULL), - m_bufferSize(0), - m_trueHDoffset(0) -@@ -51,22 +52,26 @@ bool CDVDAudioCodecPassthrough::Open(CDVDStreamInfo &hints, CDVDCodecOptions &op - case AV_CODEC_ID_AC3: - format.m_streamInfo.m_type = CAEStreamInfo::STREAM_TYPE_AC3; - format.m_streamInfo.m_sampleRate = hints.samplerate; -+ m_processInfo.SetAudioDecoderName("PT_AC3"); - break; - - case AV_CODEC_ID_EAC3: - format.m_streamInfo.m_type = CAEStreamInfo::STREAM_TYPE_EAC3; - format.m_streamInfo.m_sampleRate = hints.samplerate; -+ m_processInfo.SetAudioDecoderName("PT_EAC3"); - break; - - case AV_CODEC_ID_DTS: - format.m_streamInfo.m_type = CAEStreamInfo::STREAM_TYPE_DTSHD; - format.m_streamInfo.m_sampleRate = hints.samplerate; -+ m_processInfo.SetAudioDecoderName("PT_DTSHD"); - break; - - case AV_CODEC_ID_TRUEHD: - format.m_streamInfo.m_type = CAEStreamInfo::STREAM_TYPE_TRUEHD; - format.m_streamInfo.m_sampleRate = hints.samplerate; - m_trueHDBuffer.reset(new uint8_t[TRUEHD_BUF_SIZE]); -+ m_processInfo.SetAudioDecoderName("PT_TRUEHD"); - break; - - default: -@@ -83,6 +88,8 @@ bool CDVDAudioCodecPassthrough::Open(CDVDStreamInfo &hints, CDVDCodecOptions &op - - // only get the dts core from the parser if we don't support dtsHD - m_parser.SetCoreOnly(true); -+ -+ m_processInfo.SetAudioDecoderName("PT_DTS"); - } - - m_dataSize = 0; -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.h b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.h -index a04e736..4005429 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.h -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.h -@@ -29,10 +29,12 @@ - #include "cores/AudioEngine/Utils/AEStreamInfo.h" - #include "cores/AudioEngine/Utils/AEBitstreamPacker.h" - -+class CProcessInfo; -+ - class CDVDAudioCodecPassthrough : public CDVDAudioCodec - { - public: -- CDVDAudioCodecPassthrough(); -+ CDVDAudioCodecPassthrough(CProcessInfo &processInfo); - virtual ~CDVDAudioCodecPassthrough(); - - virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options); -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.cpp -index bb5bfe0..9717412 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.cpp -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.cpp -@@ -173,7 +173,7 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, CProces - return nullptr;; - } - --CDVDAudioCodec* CDVDFactoryCodec::CreateAudioCodec(CDVDStreamInfo &hint, bool allowpassthrough, bool allowdtshddecode) -+CDVDAudioCodec* CDVDFactoryCodec::CreateAudioCodec(CDVDStreamInfo &hint, CProcessInfo &processInfo, bool allowpassthrough, bool allowdtshddecode) - { - CDVDAudioCodec* pCodec = NULL; - CDVDCodecOptions options; -@@ -184,12 +184,12 @@ CDVDAudioCodec* CDVDFactoryCodec::CreateAudioCodec(CDVDStreamInfo &hint, bool al - // we don't use passthrough if "sync playback to display" is enabled - if (allowpassthrough) - { -- pCodec = OpenCodec(new CDVDAudioCodecPassthrough(), hint, options); -+ pCodec = OpenCodec(new CDVDAudioCodecPassthrough(processInfo), hint, options); - if (pCodec) - return pCodec; - } - -- pCodec = OpenCodec(new CDVDAudioCodecFFmpeg(), hint, options); -+ pCodec = OpenCodec(new CDVDAudioCodecFFmpeg(processInfo), hint, options); - if (pCodec) - return pCodec; - -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.h b/xbmc/cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.h -index 45e794b98..d11c700 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.h -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.h -@@ -41,7 +41,8 @@ class CDVDFactoryCodec - static CDVDVideoCodec* CreateVideoCodec(CDVDStreamInfo &hint, - CProcessInfo &processInfo, - const CRenderInfo &info = CRenderInfo()); -- static CDVDAudioCodec* CreateAudioCodec(CDVDStreamInfo &hint, bool allowpassthrough = true, bool allowdtshddecode = true); -+ static CDVDAudioCodec* CreateAudioCodec(CDVDStreamInfo &hint, CProcessInfo &processInfo, -+ bool allowpassthrough = true, bool allowdtshddecode = true); - static CDVDOverlayCodec* CreateOverlayCodec(CDVDStreamInfo &hint ); - - static CDVDAudioCodec* OpenCodec(CDVDAudioCodec* pCodec, CDVDStreamInfo &hint, CDVDCodecOptions &options ); -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -index 0414d85..967d518 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -@@ -68,6 +68,7 @@ extern "C" { - #include "libavfilter/avfilter.h" - #include "libavfilter/buffersink.h" - #include "libavfilter/buffersrc.h" -+#include "libavutil/pixdesc.h" - } - - enum DecoderState -@@ -88,11 +89,12 @@ enum EFilterFlags { - FILTER_ROTATE = 0x40, //< rotate image according to the codec hints - }; - --enum AVPixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx -- , const AVPixelFormat * fmt ) -+enum AVPixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avctx, const AVPixelFormat * fmt) - { - CDVDVideoCodecFFmpeg* ctx = (CDVDVideoCodecFFmpeg*)avctx->opaque; - -+ const char* pixFmtName = av_get_pix_fmt_name(*fmt); -+ - // if frame threading is enabled hw accel is not allowed - if(ctx->m_decoderState != STATE_HW_SINGLE) - { -@@ -122,9 +124,10 @@ enum AVPixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avct - if(VDPAU::CDecoder::IsVDPAUFormat(*cur) && CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_USEVDPAU)) - { - CLog::Log(LOGNOTICE,"CDVDVideoCodecFFmpeg::GetFormat - Creating VDPAU(%ix%i)", avctx->width, avctx->height); -- VDPAU::CDecoder* vdp = new VDPAU::CDecoder(); -+ VDPAU::CDecoder* vdp = new VDPAU::CDecoder(ctx->m_processInfo); - if(vdp->Open(avctx, ctx->m_pCodecContext, *cur, ctx->m_uSurfacesCount)) - { -+ ctx->m_processInfo.SetVideoPixelFormat(pixFmtName ? pixFmtName : ""); - ctx->SetHardware(vdp); - return *cur; - } -@@ -137,9 +140,10 @@ enum AVPixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avct - !ctx->m_hints.dvd && !ctx->m_hints.stills) - { - CLog::Log(LOGNOTICE, "CDVDVideoCodecFFmpeg::GetFormat - Creating DXVA(%ix%i)", avctx->width, avctx->height); -- DXVA::CDecoder* dec = new DXVA::CDecoder(); -+ DXVA::CDecoder* dec = new DXVA::CDecoder(ctx->m_processInfo); - if(dec->Open(avctx, ctx->m_pCodecContext, *cur, ctx->m_uSurfacesCount)) - { -+ ctx->m_processInfo.SetVideoPixelFormat(pixFmtName ? pixFmtName : ""); - ctx->SetHardware(dec); - return *cur; - } -@@ -151,9 +155,10 @@ enum AVPixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avct - // mpeg4 vaapi decoding is disabled - if(*cur == AV_PIX_FMT_VAAPI_VLD && CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_USEVAAPI)) - { -- VAAPI::CDecoder* dec = new VAAPI::CDecoder(); -+ VAAPI::CDecoder* dec = new VAAPI::CDecoder(ctx->m_processInfo); - if(dec->Open(avctx, ctx->m_pCodecContext, *cur, ctx->m_uSurfacesCount) == true) - { -+ ctx->m_processInfo.SetVideoPixelFormat(pixFmtName ? pixFmtName : ""); - ctx->SetHardware(dec); - return *cur; - } -@@ -165,9 +170,10 @@ enum AVPixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avct - #ifdef TARGET_DARWIN - if (*cur == AV_PIX_FMT_VIDEOTOOLBOX && CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_USEVTB)) - { -- VTB::CDecoder* dec = new VTB::CDecoder(); -+ VTB::CDecoder* dec = new VTB::CDecoder(ctx->m_processInfo); - if(dec->Open(avctx, ctx->m_pCodecContext, *cur, ctx->m_uSurfacesCount)) - { -+ ctx->m_processInfo.SetVideoPixelFormat(pixFmtName ? pixFmtName : ""); - ctx->SetHardware(dec); - return *cur; - } -@@ -183,6 +189,7 @@ enum AVPixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avct - ctx->m_pCodecContext->hwaccel_context = (void *)ctx->m_options.m_opaque_pointer; - if(dec->Open(avctx, ctx->m_pCodecContext, *cur, ctx->m_uSurfacesCount)) - { -+ ctx->m_processInfo.SetVideoPixelFormat(pixFmtName ? pixFmtName : ""); - ctx->SetHardware(dec); - return *cur; - } -@@ -193,6 +200,7 @@ enum AVPixelFormat CDVDVideoCodecFFmpeg::GetFormat( struct AVCodecContext * avct - cur++; - } - -+ ctx->m_processInfo.SetVideoPixelFormat(pixFmtName ? pixFmtName : ""); - ctx->m_decoderState = STATE_HW_FAILED; - return avcodec_default_get_format(avctx, fmt); - } -@@ -226,6 +234,7 @@ CDVDVideoCodecFFmpeg::CDVDVideoCodecFFmpeg(CProcessInfo &processInfo) : CDVDVide - m_skippedDeint = 0; - m_droppedFrames = 0; - m_interlaced = false; -+ m_DAR = 1.0; - } - - CDVDVideoCodecFFmpeg::~CDVDVideoCodecFFmpeg() -@@ -385,6 +394,9 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options - } - - UpdateName(); -+ -+ m_processInfo.SetVideoDecoderName(m_name, m_pHardware ? true : false); -+ m_processInfo.SetVideoDimensions(m_pCodecContext->coded_width, m_pCodecContext->coded_height); - return true; - } - -@@ -746,6 +758,12 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(DVDVideoPicture* pDvdVideoPicture) - if (aspect_ratio <= 0.0) - aspect_ratio = (float)pDvdVideoPicture->iWidth / (float)pDvdVideoPicture->iHeight; - -+ if (m_DAR != aspect_ratio) -+ { -+ m_DAR = aspect_ratio; -+ m_processInfo.SetVideoDAR(m_DAR); -+ } -+ - /* XXX: we suppose the screen has a 1.0 pixel ratio */ // CDVDVideo will compensate it. - pDvdVideoPicture->iDisplayHeight = pDvdVideoPicture->iHeight; - pDvdVideoPicture->iDisplayWidth = ((int)RINT(pDvdVideoPicture->iHeight * aspect_ratio)) & -3; -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h -index 4ef2982..20bc1ff 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h -@@ -119,6 +119,7 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec - bool m_requestSkipDeint; - int m_codecControlFlags; - bool m_interlaced; -+ double m_DAR; - CDVDStreamInfo m_hints; - CDVDCodecOptions m_options; - }; -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp -index f8730c5..fb83b42 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.cpp -@@ -29,6 +29,7 @@ - #include <d3d11.h> - #include <Initguid.h> - #include <windows.h> -+#include "cores/VideoPlayer/Process/ProcessInfo.h" - #include "cores/VideoPlayer/VideoRenderers/RenderManager.h" - #include "../DVDCodecUtils.h" - #include "DXVA.h" -@@ -689,8 +690,9 @@ CRenderPicture::~CRenderPicture() - // DXVA Decoder - //----------------------------------------------------------------------------- - --CDecoder::CDecoder() -- : m_event(true) -+CDecoder::CDecoder(CProcessInfo& processInfo) -+ : m_event(true), -+ m_processInfo(processInfo) - { - m_event.Set(); - m_state = DXVA_OPEN; -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.h -index ab756f7..2170515 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.h -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DXVA.h -@@ -28,6 +28,8 @@ - #include "libavcodec/d3d11va.h" - #include "threads/Event.h" - -+class CProcessInfo; -+ - namespace DXVA { - - #define CHECK(a) \ -@@ -114,7 +116,7 @@ class CDecoder - , public ID3DResource - { - public: -- CDecoder(); -+ CDecoder(CProcessInfo& processInfo); - ~CDecoder(); - - // IHardwareDecoder overrides -@@ -163,6 +165,7 @@ class CDecoder - unsigned int m_surface_alignment; - CCriticalSection m_section; - CEvent m_event; -+ CProcessInfo& m_processInfo; - }; - - }; -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp -index c014ce2..1b4c8e8 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.cpp -@@ -24,6 +24,7 @@ - #include "DVDVideoCodec.h" - #include "cores/VideoPlayer/DVDCodecs/DVDCodecUtils.h" - #include "cores/VideoPlayer/DVDClock.h" -+#include "cores/VideoPlayer/Process/ProcessInfo.h" - #include "utils/log.h" - #include "utils/StringUtils.h" - #include "threads/SingleLock.h" -@@ -444,7 +445,9 @@ bool CVideoSurfaces::HasRefs() - // VAAPI - //----------------------------------------------------------------------------- - --CDecoder::CDecoder() : m_vaapiOutput(&m_inMsgEvent) -+CDecoder::CDecoder(CProcessInfo& processInfo) : -+ m_vaapiOutput(&m_inMsgEvent), -+ m_processInfo(processInfo) - { - m_vaapiConfig.videoSurfaces = &m_videoSurfaces; - -@@ -453,6 +456,7 @@ CDecoder::CDecoder() : m_vaapiOutput(&m_inMsgEvent) - m_vaapiConfig.context = 0; - m_vaapiConfig.contextId = VA_INVALID_ID; - m_vaapiConfig.configId = VA_INVALID_ID; -+ m_vaapiConfig.processInfo = &m_processInfo; - m_avctx = NULL; - m_getBufferError = 0; - } -@@ -2016,6 +2020,7 @@ void COutput::InitCycle() - delete m_pp; - m_pp = NULL; - DropVppProcessedPictures(); -+ m_config.processInfo->SetVideoDeintMethod("unknown"); - } - if (!m_pp) - { -@@ -2034,6 +2039,17 @@ void COutput::InitCycle() - { - m_pp->Init(method); - m_currentDiMethod = method; -+ -+ if (method == VS_INTERLACEMETHOD_DEINTERLACE) -+ m_config.processInfo->SetVideoDeintMethod("yadif"); -+ else if (method == VS_INTERLACEMETHOD_RENDER_BOB) -+ m_config.processInfo->SetVideoDeintMethod("render-bob"); -+ else if (method == VS_INTERLACEMETHOD_VAAPI_BOB) -+ m_config.processInfo->SetVideoDeintMethod("vaapi-bob"); -+ else if (method == VS_INTERLACEMETHOD_VAAPI_MADI) -+ m_config.processInfo->SetVideoDeintMethod("vaapi-madi"); -+ else if (method == VS_INTERLACEMETHOD_VAAPI_MACI) -+ m_config.processInfo->SetVideoDeintMethod("vaapi-maci"); - } - else - { -@@ -2066,6 +2082,7 @@ void COutput::InitCycle() - { - m_pp->Init(method); - m_currentDiMethod = method; -+ m_config.processInfo->SetVideoDeintMethod("none"); - } - else - { -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.h -index cc744c7..08c5dfc 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.h -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VAAPI.h -@@ -48,6 +48,7 @@ extern "C" { - - using namespace Actor; - -+class CProcessInfo; - - #define FULLHD_WIDTH 1920 - -@@ -125,6 +126,7 @@ struct CVaapiConfig - VAProfile profile; - VAConfigAttrib attrib; - Display *x11dsp; -+ CProcessInfo *processInfo; - }; - - /** -@@ -411,7 +413,7 @@ class CDecoder - - public: - -- CDecoder(); -+ CDecoder(CProcessInfo& processInfo); - virtual ~CDecoder(); - - virtual bool Open (AVCodecContext* avctx, AVCodecContext* mainctx, const enum AVPixelFormat, unsigned int surfaces = 0); -@@ -468,6 +470,7 @@ class CDecoder - - int m_codecControl; - std::vector<EINTERLACEMETHOD> m_diMethods; -+ CProcessInfo& m_processInfo; - }; - - //----------------------------------------------------------------------------- -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.cpp -index 331b719..377c72b 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.cpp -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.cpp -@@ -25,6 +25,7 @@ - #include "windowing/WindowingFactory.h" - #include "guilib/GraphicContext.h" - #include "guilib/TextureManager.h" -+#include "cores/VideoPlayer/Process/ProcessInfo.h" - #include "cores/VideoPlayer/VideoRenderers/RenderManager.h" - #include "DVDVideoCodecFFmpeg.h" - #include "DVDClock.h" -@@ -467,13 +468,14 @@ int CVideoSurfaces::Size() - // CVDPAU - //----------------------------------------------------------------------------- - --CDecoder::CDecoder() : m_vdpauOutput(&m_inMsgEvent) -+CDecoder::CDecoder(CProcessInfo& processInfo) : m_vdpauOutput(&m_inMsgEvent), m_processInfo(processInfo) - { - m_vdpauConfig.videoSurfaces = &m_videoSurfaces; - - m_vdpauConfigured = false; - m_DisplayState = VDPAU_OPEN; - m_vdpauConfig.context = 0; -+ m_vdpauConfig.processInfo = &m_processInfo; - } - - bool CDecoder::Open(AVCodecContext* avctx, AVCodecContext* mainctx, const enum AVPixelFormat fmt, unsigned int surfaces) -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.h -index 56601a1..59432ad 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.h -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VDPAU.h -@@ -70,6 +70,8 @@ extern "C" { - #define FULLHD_WIDTH 1920 - #define MAX_PIC_Q_LENGTH 20 //for non-interop_yuv this controls the max length of the decoded pic to render completion Q - -+class CProcessInfo; -+ - namespace VDPAU - { - -@@ -182,6 +184,7 @@ struct CVdpauConfig - uint32_t maxReferences; - bool useInteropYuv; - CVDPAUContext *context; -+ CProcessInfo *processInfo; - }; - - /** -@@ -556,7 +559,7 @@ class CDecoder - uint32_t aux; /* optional extra parameter... */ - }; - -- CDecoder(); -+ CDecoder(CProcessInfo& processInfo); - virtual ~CDecoder(); - - virtual bool Open (AVCodecContext* avctx, AVCodecContext* mainctx, const enum AVPixelFormat, unsigned int surfaces = 0); -@@ -623,6 +626,7 @@ class CDecoder - CVdpauRenderPicture *m_presentPicture; - - int m_codecControl; -+ CProcessInfo& m_processInfo; - }; - - } -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VTB.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VTB.cpp -index 253aefd..287b7c1 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VTB.cpp -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VTB.cpp -@@ -21,6 +21,7 @@ - #ifdef TARGET_DARWIN - #include "platform/darwin/osx/CocoaInterface.h" - #include "platform/darwin/DarwinUtils.h" -+#include "cores/VideoPlayer/Process/ProcessInfo.h" - #include "DVDVideoCodec.h" - #include "DVDCodecs/DVDCodecUtils.h" - #include "utils/log.h" -@@ -34,7 +35,7 @@ extern "C" { - using namespace VTB; - - --CDecoder::CDecoder() -+CDecoder::CDecoder(CProcessInfo& processInfo) : m_processInfo(processInfo) - { - m_avctx = nullptr; - } -@@ -86,6 +87,7 @@ bool CDecoder::Open(AVCodecContext *avctx, AVCodecContext* mainctx, enum AVPixel - mainctx->pix_fmt = fmt; - mainctx->hwaccel_context = avctx->hwaccel_context; - -+ m_processInfo.SetVideoDeintMethod("none"); - return true; - } - -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VTB.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VTB.h -index 1e097d4..bad295b 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/VTB.h -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/VTB.h -@@ -23,6 +23,8 @@ - - #include "DVDVideoCodecFFmpeg.h" - -+class CProcessInfo; -+ - namespace VTB - { - -@@ -30,7 +32,7 @@ class CDecoder - : public CDVDVideoCodecFFmpeg::IHardwareDecoder - { - public: -- CDecoder(); -+ CDecoder(CProcessInfo& processInfo); - ~CDecoder(); - virtual bool Open(AVCodecContext* avctx, AVCodecContext* mainctx, const enum AVPixelFormat, unsigned int surfaces = 0); - virtual int Decode(AVCodecContext* avctx, AVFrame* frame); -@@ -43,7 +45,7 @@ class CDecoder - protected: - unsigned m_renderbuffers_count; - AVCodecContext *m_avctx; -- -+ CProcessInfo& m_processInfo; - }; - - } -diff --git a/xbmc/cores/VideoPlayer/Process/ProcessInfo.cpp b/xbmc/cores/VideoPlayer/Process/ProcessInfo.cpp -index ceaa256..fc1f5dd 100644 ---- a/xbmc/cores/VideoPlayer/Process/ProcessInfo.cpp -+++ b/xbmc/cores/VideoPlayer/Process/ProcessInfo.cpp -@@ -19,6 +19,8 @@ - */ - - #include "ProcessInfo.h" -+#include "cores/DataCacheCore.h" -+#include "threads/SingleLock.h" - - // Override for platform ports - #if !defined(PLATFORM_OVERRIDE) -@@ -51,3 +53,200 @@ bool CProcessInfo::AllowDTSHDDecode() - { - return true; - } -+ -+void CProcessInfo::ResetVideoCodecInfo() -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ m_videoIsHWDecoder = false; -+ m_videoDecoderName = "unknown"; -+ m_videoDeintMethod = "unknown"; -+ m_videoPixelFormat = "unknown"; -+ m_videoWidth = 0; -+ m_videoHeight = 0; -+ m_videoFPS = 0.0; -+ -+ g_dataCacheCore.SetVideoDecoderName(m_videoDecoderName, m_videoIsHWDecoder); -+ g_dataCacheCore.SetVideoDeintMethod(m_videoDeintMethod); -+ g_dataCacheCore.SetVideoPixelFormat(m_videoPixelFormat); -+ g_dataCacheCore.SetVideoDimensions(m_videoWidth, m_videoHeight); -+ g_dataCacheCore.SetVideoFps(m_videoFPS); -+} -+ -+void CProcessInfo::SetVideoDecoderName(std::string name, bool isHw) -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ m_videoIsHWDecoder = isHw; -+ m_videoDecoderName = name; -+ -+ g_dataCacheCore.SetVideoDecoderName(m_videoDecoderName, m_videoIsHWDecoder); -+} -+ -+std::string CProcessInfo::GetVideoDecoderName() -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ return m_videoDecoderName; -+} -+ -+bool CProcessInfo::IsVideoHwDecoder() -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ return m_videoIsHWDecoder; -+} -+ -+void CProcessInfo::SetVideoDeintMethod(std::string method) -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ m_videoDeintMethod = method; -+ -+ g_dataCacheCore.SetVideoDeintMethod(m_videoDeintMethod); -+} -+ -+std::string CProcessInfo::GetVideoDeintMethod() -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ return m_videoDeintMethod; -+} -+ -+void CProcessInfo::SetVideoPixelFormat(std::string pixFormat) -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ m_videoPixelFormat = pixFormat; -+ -+ g_dataCacheCore.SetVideoPixelFormat(m_videoPixelFormat); -+} -+ -+std::string CProcessInfo::GetVideoPixelFormat() -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ return m_videoPixelFormat; -+} -+ -+void CProcessInfo::SetVideoDimensions(int width, int height) -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ m_videoWidth = width; -+ m_videoHeight = height; -+ -+ g_dataCacheCore.SetVideoDimensions(m_videoWidth, m_videoHeight); -+} -+ -+void CProcessInfo::GetVideoDimensions(int &width, int &height) -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ width = m_videoWidth; -+ height = m_videoHeight; -+} -+ -+void CProcessInfo::SetVideoFps(float fps) -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ m_videoFPS = fps; -+ -+ g_dataCacheCore.SetVideoFps(m_videoFPS); -+} -+ -+float CProcessInfo::GetVideoFps() -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ return m_videoFPS; -+} -+ -+void CProcessInfo::SetVideoDAR(float dar) -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ m_videoDAR = dar; -+ -+ CServiceBroker::GetDataCacheCore().SetVideoDAR(m_videoDAR); -+} -+ -+float CProcessInfo::GetVideoDAR() -+{ -+ CSingleLock lock(m_videoCodecSection); -+ -+ return m_videoDAR; -+} -+ -+// player audio info -+void CProcessInfo::ResetAudioCodecInfo() -+{ -+ CSingleLock lock(m_audioCodecSection); -+ -+ m_audioDecoderName = "unknown"; -+ m_audioChannels = "unknown"; -+ m_audioSampleRate = 0;; -+ m_audioBitsPerSample = 0; -+ -+ g_dataCacheCore.SetAudioDecoderName(m_audioDecoderName); -+ g_dataCacheCore.SetAudioChannels(m_audioChannels); -+ g_dataCacheCore.SetAudioSampleRate(m_audioSampleRate); -+ g_dataCacheCore.SetAudioBitsPerSample(m_audioBitsPerSample); -+} -+ -+void CProcessInfo::SetAudioDecoderName(std::string name) -+{ -+ CSingleLock lock(m_audioCodecSection); -+ -+ m_audioDecoderName = name; -+} -+ -+std::string CProcessInfo::GetAudioDecoderName() -+{ -+ CSingleLock lock(m_audioCodecSection); -+ -+ return m_audioDecoderName; -+} -+ -+void CProcessInfo::SetAudioChannels(std::string channels) -+{ -+ CSingleLock lock(m_audioCodecSection); -+ -+ m_audioChannels = channels; -+} -+ -+std::string CProcessInfo::GetAudioChannels() -+{ -+ CSingleLock lock(m_audioCodecSection); -+ -+ return m_audioChannels; -+} -+ -+void CProcessInfo::SetAudioSampleRate(int sampleRate) -+{ -+ CSingleLock lock(m_audioCodecSection); -+ -+ m_audioSampleRate = sampleRate; -+} -+ -+int CProcessInfo::GetAudioSampleRate() -+{ -+ CSingleLock lock(m_audioCodecSection); -+ -+ return m_audioSampleRate; -+} -+ -+void CProcessInfo::SetAudioBitsPerSample(int bitsPerSample) -+{ -+ CSingleLock lock(m_audioCodecSection); -+ -+ m_audioBitsPerSample = bitsPerSample; -+} -+ -+int CProcessInfo::GetAudioBitsPerSampe() -+{ -+ CSingleLock lock(m_audioCodecSection); -+ -+ return m_audioBitsPerSample; -+} -diff --git a/xbmc/cores/VideoPlayer/Process/ProcessInfo.h b/xbmc/cores/VideoPlayer/Process/ProcessInfo.h -index b8a4e46..0ec9a2c 100644 ---- a/xbmc/cores/VideoPlayer/Process/ProcessInfo.h -+++ b/xbmc/cores/VideoPlayer/Process/ProcessInfo.h -@@ -20,6 +20,8 @@ - #pragma once - - #include "cores/IPlayer.h" -+#include "threads/CriticalSection.h" -+#include <string> - - class CProcessInfo - { -@@ -29,6 +31,51 @@ class CProcessInfo - virtual EINTERLACEMETHOD GetFallbackDeintMethod(); - virtual bool AllowDTSHDDecode(); - -+ // player video info -+ void ResetVideoCodecInfo(); -+ void SetVideoDecoderName(std::string name, bool isHw); -+ std::string GetVideoDecoderName(); -+ bool IsVideoHwDecoder(); -+ void SetVideoDeintMethod(std::string method); -+ std::string GetVideoDeintMethod(); -+ void SetVideoPixelFormat(std::string pixFormat); -+ std::string GetVideoPixelFormat(); -+ void SetVideoDimensions(int width, int height); -+ void GetVideoDimensions(int &width, int &height); -+ void SetVideoFps(float fps); -+ float GetVideoFps(); -+ void SetVideoDAR(float dar); -+ float GetVideoDAR(); -+ -+ // player audio info -+ void ResetAudioCodecInfo(); -+ void SetAudioDecoderName(std::string name); -+ std::string GetAudioDecoderName(); -+ void SetAudioChannels(std::string channels); -+ std::string GetAudioChannels(); -+ void SetAudioSampleRate(int sampleRate); -+ int GetAudioSampleRate(); -+ void SetAudioBitsPerSample(int bitsPerSample); -+ int GetAudioBitsPerSampe(); -+ - protected: - CProcessInfo(); -+ -+ // player video info -+ bool m_videoIsHWDecoder; -+ std::string m_videoDecoderName; -+ std::string m_videoDeintMethod; -+ std::string m_videoPixelFormat; -+ int m_videoWidth; -+ int m_videoHeight; -+ float m_videoFPS; -+ float m_videoDAR; -+ CCriticalSection m_videoCodecSection; -+ -+ // player audio info -+ std::string m_audioDecoderName; -+ std::string m_audioChannels; -+ int m_audioSampleRate; -+ int m_audioBitsPerSample; -+ CCriticalSection m_audioCodecSection; - }; -diff --git a/xbmc/cores/VideoPlayer/VideoPlayerAudio.cpp b/xbmc/cores/VideoPlayer/VideoPlayerAudio.cpp -index fb1d993..2422815 100644 ---- a/xbmc/cores/VideoPlayer/VideoPlayerAudio.cpp -+++ b/xbmc/cores/VideoPlayer/VideoPlayerAudio.cpp -@@ -90,11 +90,13 @@ CVideoPlayerAudio::~CVideoPlayerAudio() - - bool CVideoPlayerAudio::OpenStream(CDVDStreamInfo &hints) - { -+ m_processInfo.ResetAudioCodecInfo(); -+ - CLog::Log(LOGNOTICE, "Finding audio codec for: %i", hints.codec); - bool allowpassthrough = !CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_USEDISPLAYASCLOCK); - if (hints.realtime) - allowpassthrough = false; -- CDVDAudioCodec* codec = CDVDFactoryCodec::CreateAudioCodec(hints, allowpassthrough, m_processInfo.AllowDTSHDDecode()); -+ CDVDAudioCodec* codec = CDVDFactoryCodec::CreateAudioCodec(hints, m_processInfo, allowpassthrough, m_processInfo.AllowDTSHDDecode()); - if(!codec) - { - CLog::Log(LOGERROR, "Unsupported audio codec"); -@@ -451,6 +453,11 @@ void CVideoPlayerAudio::Process() - - m_streaminfo.channels = audioframe.format.m_channelLayout.Count(); - -+ -+ m_processInfo.SetAudioChannels(audioframe.format.m_channelLayout); -+ m_processInfo.SetAudioSampleRate(audioframe.format.m_sampleRate); -+ m_processInfo.SetAudioBitsPerSample(audioframe.bits_per_sample); -+ - m_messageParent.Put(new CDVDMsg(CDVDMsg::PLAYER_AVCHANGE)); - } - -@@ -595,7 +602,7 @@ bool CVideoPlayerAudio::SwitchCodecIfNeeded() - bool allowpassthrough = !CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_USEDISPLAYASCLOCK); - if (m_streaminfo.realtime) - allowpassthrough = false; -- CDVDAudioCodec *codec = CDVDFactoryCodec::CreateAudioCodec(m_streaminfo, allowpassthrough, m_processInfo.AllowDTSHDDecode()); -+ CDVDAudioCodec *codec = CDVDFactoryCodec::CreateAudioCodec(m_streaminfo, m_processInfo, allowpassthrough, m_processInfo.AllowDTSHDDecode()); - if (!codec || codec->NeedPassthrough() == m_pAudioCodec->NeedPassthrough()) { - // passthrough state has not changed - delete codec; -diff --git a/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp b/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp -index 8e5d33dc..fd260d43 100644 ---- a/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp -+++ b/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp -@@ -120,6 +120,8 @@ double CVideoPlayerVideo::GetOutputDelay() - - bool CVideoPlayerVideo::OpenStream( CDVDStreamInfo &hint ) - { -+ m_processInfo.ResetVideoCodecInfo(); -+ - CRenderInfo info; - info = m_renderManager.GetRenderInfo(); - -@@ -156,11 +158,13 @@ void CVideoPlayerVideo::OpenStream(CDVDStreamInfo &hint, CDVDVideoCodec* codec) - { - m_fFrameRate = DVD_TIME_BASE / CDVDCodecUtils::NormalizeFrameduration((double)DVD_TIME_BASE * hint.fpsscale / hint.fpsrate); - m_bFpsInvalid = false; -+ m_processInfo.SetVideoFps(m_fFrameRate); - } - else - { - m_fFrameRate = 25; - m_bFpsInvalid = true; -+ m_processInfo.SetVideoFps(0); - } - - m_pullupCorrection.ResetVFRDetection(); -@@ -1023,6 +1027,7 @@ void CVideoPlayerVideo::CalcFrameRate() - CLog::Log(LOGDEBUG,"%s framerate was:%f calculated:%f", __FUNCTION__, m_fFrameRate, m_fStableFrameRate / m_iFrameRateCount); - m_fFrameRate = m_fStableFrameRate / m_iFrameRateCount; - m_bFpsInvalid = false; -+ m_processInfo.SetVideoFps(m_fFrameRate); - } - - //reset the stored framerates -diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp -index 50a5b17..6161962 100644 ---- a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp -+++ b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp -@@ -100,6 +100,7 @@ bool OMXPlayerAudio::OpenStream(CDVDStreamInfo &hints) - { - m_bad_state = false; - -+ m_processInfo.ResetAudioCodecInfo(); - COMXAudioCodecOMX *codec = new COMXAudioCodecOMX(); - - if(!codec || !codec->Open(hints)) -diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -index 236f1b3..0ec7f15 100644 ---- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -@@ -515,6 +515,8 @@ bool OMXPlayerVideo::OpenDecoder() - if(!m_av_clock) - return false; - -+ m_processInfo.ResetVideoCodecInfo(); -+ - if (m_hints.fpsrate && m_hints.fpsscale) - m_fFrameRate = DVD_TIME_BASE / CDVDCodecUtils::NormalizeFrameduration((double)DVD_TIME_BASE * m_hints.fpsscale / m_hints.fpsrate); - else -@@ -525,6 +527,8 @@ bool OMXPlayerVideo::OpenDecoder() - CLog::Log(LOGINFO, "OMXPlayerVideo::OpenDecoder : Invalid framerate %d, using forced 25fps and just trust timestamps\n", (int)m_fFrameRate); - m_fFrameRate = 25; - } -+ m_processInfo.SetVideoFps(m_fFrameRate); -+ - // use aspect in stream if available - if (m_hints.forced_aspect) - m_fForcedAspectRatio = m_hints.aspect; -@@ -705,6 +709,9 @@ void OMXPlayerVideo::ResolutionUpdateCallBack(uint32_t width, uint32_t height, f - m_bAllowFullscreen = false; // only allow on first configure - } - -+ m_processInfo.SetVideoDimensions(width, height); -+ m_processInfo.SetVideoAspectRatio(display_aspect); -+ - unsigned int iDisplayWidth = width; - unsigned int iDisplayHeight = height; - -diff --git a/xbmc/cores/paplayer/VideoPlayerCodec.cpp b/xbmc/cores/paplayer/VideoPlayerCodec.cpp -index 9056cf8..32add6c 100644 ---- a/xbmc/cores/paplayer/VideoPlayerCodec.cpp -+++ b/xbmc/cores/paplayer/VideoPlayerCodec.cpp -@@ -46,6 +46,8 @@ VideoPlayerCodec::VideoPlayerCodec() - m_pResampler = NULL; - m_needConvert = false; - m_channels = 0; -+ -+ m_processInfo.reset(CProcessInfo::CreateInstance()); - } - - VideoPlayerCodec::~VideoPlayerCodec() -@@ -165,7 +167,7 @@ bool VideoPlayerCodec::Init(const CFileItem &file, unsigned int filecache) - - CDVDStreamInfo hint(*pStream, true); - -- m_pAudioCodec = CDVDFactoryCodec::CreateAudioCodec(hint); -+ m_pAudioCodec = CDVDFactoryCodec::CreateAudioCodec(hint, *m_processInfo.get()); - if (!m_pAudioCodec) - { - CLog::Log(LOGERROR, "%s: Could not create audio codec", __FUNCTION__); -diff --git a/xbmc/cores/paplayer/VideoPlayerCodec.h b/xbmc/cores/paplayer/VideoPlayerCodec.h -index 81379bd..042f4f7 100644 ---- a/xbmc/cores/paplayer/VideoPlayerCodec.h -+++ b/xbmc/cores/paplayer/VideoPlayerCodec.h -@@ -73,6 +73,8 @@ class VideoPlayerCodec : public ICodec - bool m_needConvert; - AEAudioFormat m_srcFormat; - int m_channels; -+ -+ std::unique_ptr<CProcessInfo> m_processInfo; - }; - - #endif -diff --git a/xbmc/guiinfo/GUIInfoLabels.h b/xbmc/guiinfo/GUIInfoLabels.h -index 27d6bc2..96edafa 100644 ---- a/xbmc/guiinfo/GUIInfoLabels.h -+++ b/xbmc/guiinfo/GUIInfoLabels.h -@@ -562,6 +562,20 @@ - #define RDS_CHANNEL_COUNTRY (RDS_DATA_START + 44) - #define RDS_DATA_END RDS_CHANNEL_COUNTRY - -+#define PLAYER_PROCESS 1500 -+#define PLAYER_PROCESS_VIDEODECODER (PLAYER_PROCESS) -+#define PLAYER_PROCESS_DEINTMETHOD (PLAYER_PROCESS + 1) -+#define PLAYER_PROCESS_PIXELFORMAT (PLAYER_PROCESS + 2) -+#define PLAYER_PROCESS_VIDEOWIDTH (PLAYER_PROCESS + 3) -+#define PLAYER_PROCESS_VIDEOHEIGHT (PLAYER_PROCESS + 4) -+#define PLAYER_PROCESS_VIDEOFPS (PLAYER_PROCESS + 5) -+#define PLAYER_PROCESS_VIDEODAR (PLAYER_PROCESS + 6) -+#define PLAYER_PROCESS_VIDEOHWDECODER (PLAYER_PROCESS + 7) -+#define PLAYER_PROCESS_AUDIODECODER (PLAYER_PROCESS + 8) -+#define PLAYER_PROCESS_AUDIOCHANNELS (PLAYER_PROCESS + 9) -+#define PLAYER_PROCESS_AUDIOSAMPLERATE (PLAYER_PROCESS + 10) -+#define PLAYER_PROCESS_AUDIOBITSPERSAMPLE (PLAYER_PROCESS + 11) -+ - #define WINDOW_PROPERTY 9993 - #define WINDOW_IS_TOPMOST 9994 - #define WINDOW_IS_VISIBLE 9995 - -From 6855680f52c826aa2a2e2684c5607e00a6f8fff1 Mon Sep 17 00:00:00 2001 -From: Rainer Hochecker <fernetmenta@online.de> -Date: Wed, 22 Jun 2016 18:48:10 +0200 -Subject: [PATCH 2/3] remove DataCacheCore from systemGlobals - ---- - xbmc/Application.cpp | 1 + - xbmc/GUIInfoManager.cpp | 24 ++++++++++----------- - xbmc/ServiceBroker.cpp | 5 +++++ - xbmc/ServiceBroker.h | 2 ++ - xbmc/ServiceManager.cpp | 7 +++++++ - xbmc/ServiceManager.h | 3 +++ - xbmc/SystemGlobals.cpp | 4 ---- - xbmc/cores/DataCacheCore.cpp | 6 ++++++ - xbmc/cores/DataCacheCore.h | 5 ++--- - xbmc/cores/VideoPlayer/Process/ProcessInfo.cpp | 29 +++++++++++++------------- - xbmc/cores/VideoPlayer/VideoPlayer.cpp | 14 +++++++------ - xbmc/cores/paplayer/PAPlayer.cpp | 3 ++- - 12 files changed, 63 insertions(+), 40 deletions(-) - -diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp -index cdcf53e..baada48 100644 ---- a/xbmc/Application.cpp -+++ b/xbmc/Application.cpp -@@ -37,6 +37,7 @@ - #include "cores/AudioEngine/AEFactory.h" - #include "cores/AudioEngine/Engines/ActiveAE/AudioDSPAddons/ActiveAEDSP.h" - #include "cores/AudioEngine/Utils/AEUtil.h" -+#include "cores/DataCacheCore.h" - #include "cores/playercorefactory/PlayerCoreFactory.h" - #include "PlayListPlayer.h" - #include "Autorun.h" -diff --git a/xbmc/GUIInfoManager.cpp b/xbmc/GUIInfoManager.cpp -index ab5cb12..7d42106 100644 ---- a/xbmc/GUIInfoManager.cpp -+++ b/xbmc/GUIInfoManager.cpp -@@ -6018,25 +6018,25 @@ std::string CGUIInfoManager::GetLabel(int info, int contextWindow, std::string * - } - break; - case PLAYER_PROCESS_VIDEODECODER: -- strLabel = g_dataCacheCore.GetVideoDecoderName(); -+ strLabel = CServiceBroker::GetDataCacheCore().GetVideoDecoderName(); - break; - case PLAYER_PROCESS_DEINTMETHOD: -- strLabel = g_dataCacheCore.GetVideoDeintMethod(); -+ strLabel = CServiceBroker::GetDataCacheCore().GetVideoDeintMethod(); - break; - case PLAYER_PROCESS_PIXELFORMAT: -- strLabel = g_dataCacheCore.GetVideoPixelFormat(); -+ strLabel = CServiceBroker::GetDataCacheCore().GetVideoPixelFormat(); - break; - case PLAYER_PROCESS_VIDEOFPS: -- strLabel = StringUtils::FormatNumber(g_dataCacheCore.GetVideoFps()); -+ strLabel = StringUtils::FormatNumber(CServiceBroker::GetDataCacheCore().GetVideoFps()); - break; - case PLAYER_PROCESS_VIDEODAR: - strLabel = StringUtils::FormatNumber(CServiceBroker::GetDataCacheCore().GetVideoDAR()); - break; - case PLAYER_PROCESS_AUDIODECODER: -- strLabel = g_dataCacheCore.GetAudioDecoderName(); -+ strLabel = CServiceBroker::GetDataCacheCore().GetAudioDecoderName(); - break; - case PLAYER_PROCESS_AUDIOCHANNELS: -- strLabel = g_dataCacheCore.GetAudioChannels(); -+ strLabel = CServiceBroker::GetDataCacheCore().GetAudioChannels(); - break; - case RDS_AUDIO_LANG: - case RDS_CHANNEL_COUNTRY: -@@ -6601,16 +6601,16 @@ bool CGUIInfoManager::GetInt(int &value, int info, int contextWindow, const CGUI - value = g_powerManager.BatteryLevel(); - return true; - case PLAYER_PROCESS_VIDEOWIDTH: -- value = g_dataCacheCore.GetVideoWidth(); -+ value = CServiceBroker::GetDataCacheCore().GetVideoWidth(); - return true; - case PLAYER_PROCESS_VIDEOHEIGHT: -- value = g_dataCacheCore.GetVideoHeight(); -+ value = CServiceBroker::GetDataCacheCore().GetVideoHeight(); - return true; - case PLAYER_PROCESS_AUDIOSAMPLERATE: -- value = g_dataCacheCore.GetAudioSampleRate(); -+ value = CServiceBroker::GetDataCacheCore().GetAudioSampleRate(); - return true; - case PLAYER_PROCESS_AUDIOBITSPERSAMPLE: -- value = g_dataCacheCore.GetAudioBitsPerSampe(); -+ value = CServiceBroker::GetDataCacheCore().GetAudioBitsPerSampe(); - return true; - } - return false; -@@ -7148,7 +7148,7 @@ bool CGUIInfoManager::GetBool(int condition1, int contextWindow, const CGUIListI - !m_currentFile->GetPVRRadioRDSInfoTag()->GetPhoneStudio().empty()); - break; - case PLAYER_PROCESS_VIDEOHWDECODER: -- bReturn = g_dataCacheCore.IsVideoHwDecoder(); -+ bReturn = CServiceBroker::GetDataCacheCore().IsVideoHwDecoder(); - break; - default: // default, use integer value different from 0 as true - { -@@ -9150,7 +9150,7 @@ void CGUIInfoManager::UpdateAVInfo() - { - if(g_application.m_pPlayer->IsPlaying()) - { -- if (g_dataCacheCore.HasAVInfoChanges()) -+ if (CServiceBroker::GetDataCacheCore().HasAVInfoChanges()) - { - SPlayerVideoStreamInfo video; - SPlayerAudioStreamInfo audio; -diff --git a/xbmc/ServiceBroker.cpp b/xbmc/ServiceBroker.cpp -index fff03c3..dd5c640 100644 ---- a/xbmc/ServiceBroker.cpp -+++ b/xbmc/ServiceBroker.cpp -@@ -50,3 +50,8 @@ ActiveAE::CActiveAEDSP &CServiceBroker::GetADSP() - { - return g_application.m_ServiceManager->GetADSPManager(); - } -+ -+CDataCacheCore &CServiceBroker::GetDataCacheCore() -+{ -+ return g_application.m_ServiceManager->GetDataCacheCore(); -+} -diff --git a/xbmc/ServiceBroker.h b/xbmc/ServiceBroker.h -index 32add30..9f9de19 100644 ---- a/xbmc/ServiceBroker.h -+++ b/xbmc/ServiceBroker.h -@@ -40,6 +40,7 @@ namespace PVR - } - - class XBPython; -+class CDataCacheCore; - - class CServiceBroker - { -@@ -50,4 +51,5 @@ class CServiceBroker - static XBPython &GetXBPython(); - static PVR::CPVRManager &GetPVRManager(); - static ActiveAE::CActiveAEDSP& GetADSP(); -+ static CDataCacheCore& GetDataCacheCore(); - }; -diff --git a/xbmc/ServiceManager.cpp b/xbmc/ServiceManager.cpp -index 3cc188c..4cf4440 100644 ---- a/xbmc/ServiceManager.cpp -+++ b/xbmc/ServiceManager.cpp -@@ -21,6 +21,7 @@ - #include "ServiceManager.h" - #include "addons/BinaryAddonCache.h" - #include "cores/AudioEngine/Engines/ActiveAE/AudioDSPAddons/ActiveAEDSP.h" -+#include "cores/DataCacheCore.h" - #include "utils/log.h" - #include "interfaces/AnnouncementManager.h" - #include "interfaces/generic/ScriptInvocationManager.h" -@@ -49,6 +50,7 @@ bool CServiceManager::Init2() - - m_ADSPManager.reset(new ActiveAE::CActiveAEDSP()); - m_PVRManager.reset(new PVR::CPVRManager()); -+ m_dataCacheCore.reset(new CDataCacheCore()); - - m_binaryAddonCache.reset( new ADDON::CBinaryAddonCache()); - m_binaryAddonCache->Init(); -@@ -104,3 +106,8 @@ ActiveAE::CActiveAEDSP& CServiceManager::GetADSPManager() - { - return *m_ADSPManager; - } -+ -+CDataCacheCore& CServiceManager::GetDataCacheCore() -+{ -+ return *m_dataCacheCore; -+} -\ No newline at end of file -diff --git a/xbmc/ServiceManager.h b/xbmc/ServiceManager.h -index 9b7806f6..5c7a9a8 100644 ---- a/xbmc/ServiceManager.h -+++ b/xbmc/ServiceManager.h -@@ -42,6 +42,7 @@ class CPVRManager; - } - - class XBPython; -+class CDataCacheCore; - - class CServiceManager - { -@@ -56,6 +57,7 @@ class CServiceManager - XBPython& GetXBPython(); - PVR::CPVRManager& GetPVRManager(); - ActiveAE::CActiveAEDSP& GetADSPManager(); -+ CDataCacheCore& GetDataCacheCore(); - - protected: - std::unique_ptr<ADDON::CAddonMgr> m_addonMgr; -@@ -64,4 +66,5 @@ class CServiceManager - std::unique_ptr<XBPython> m_XBPython; - std::unique_ptr<PVR::CPVRManager> m_PVRManager; - std::unique_ptr<ActiveAE::CActiveAEDSP> m_ADSPManager; -+ std::unique_ptr<CDataCacheCore> m_dataCacheCore; - }; -diff --git a/xbmc/SystemGlobals.cpp b/xbmc/SystemGlobals.cpp -index 9354471..3d1cb55 100644 ---- a/xbmc/SystemGlobals.cpp -+++ b/xbmc/SystemGlobals.cpp -@@ -19,7 +19,6 @@ - */ - #include "system.h" - #include "SectionLoader.h" --#include "cores/DataCacheCore.h" - #include "GUILargeTextureManager.h" - #include "guilib/TextureManager.h" - #include "utils/AlarmClock.h" -@@ -71,6 +70,3 @@ std::map<std::string, std::string> CSpecialProtocol::m_pathMap; - #endif - - CZipManager g_ZipManager; -- -- CDataCacheCore g_dataCacheCore; -- -diff --git a/xbmc/cores/DataCacheCore.cpp b/xbmc/cores/DataCacheCore.cpp -index cbb0a4f..43a24f1 100644 ---- a/xbmc/cores/DataCacheCore.cpp -+++ b/xbmc/cores/DataCacheCore.cpp -@@ -20,12 +20,18 @@ - - #include "cores/DataCacheCore.h" - #include "threads/SingleLock.h" -+#include "ServiceBroker.h" - - CDataCacheCore::CDataCacheCore() - { - m_hasAVInfoChanges = false; - } - -+CDataCacheCore& GetInstance() -+{ -+ return CServiceBroker::GetDataCacheCore(); -+} -+ - bool CDataCacheCore::HasAVInfoChanges() - { - bool ret = m_hasAVInfoChanges; -diff --git a/xbmc/cores/DataCacheCore.h b/xbmc/cores/DataCacheCore.h -index e16c81f..646f512 100644 ---- a/xbmc/cores/DataCacheCore.h -+++ b/xbmc/cores/DataCacheCore.h -@@ -28,6 +28,7 @@ class CDataCacheCore - { - public: - CDataCacheCore(); -+ static CDataCacheCore& GetInstance(); - bool HasAVInfoChanges(); - void SignalVideoInfoChange(); - void SignalAudioInfoChange(); -@@ -82,6 +83,4 @@ class CDataCacheCore - int sampleRate; - int bitsPerSample; - } m_playerAudioInfo; --}; -- --extern CDataCacheCore g_dataCacheCore; -\ No newline at end of file -+}; -\ No newline at end of file -diff --git a/xbmc/cores/VideoPlayer/Process/ProcessInfo.cpp b/xbmc/cores/VideoPlayer/Process/ProcessInfo.cpp -index fc1f5dd..bfd7d58 100644 ---- a/xbmc/cores/VideoPlayer/Process/ProcessInfo.cpp -+++ b/xbmc/cores/VideoPlayer/Process/ProcessInfo.cpp -@@ -19,6 +19,7 @@ - */ - - #include "ProcessInfo.h" -+#include "ServiceBroker.h" - #include "cores/DataCacheCore.h" - #include "threads/SingleLock.h" - -@@ -66,11 +67,11 @@ void CProcessInfo::ResetVideoCodecInfo() - m_videoHeight = 0; - m_videoFPS = 0.0; - -- g_dataCacheCore.SetVideoDecoderName(m_videoDecoderName, m_videoIsHWDecoder); -- g_dataCacheCore.SetVideoDeintMethod(m_videoDeintMethod); -- g_dataCacheCore.SetVideoPixelFormat(m_videoPixelFormat); -- g_dataCacheCore.SetVideoDimensions(m_videoWidth, m_videoHeight); -- g_dataCacheCore.SetVideoFps(m_videoFPS); -+ CServiceBroker::GetDataCacheCore().SetVideoDecoderName(m_videoDecoderName, m_videoIsHWDecoder); -+ CServiceBroker::GetDataCacheCore().SetVideoDeintMethod(m_videoDeintMethod); -+ CServiceBroker::GetDataCacheCore().SetVideoPixelFormat(m_videoPixelFormat); -+ CServiceBroker::GetDataCacheCore().SetVideoDimensions(m_videoWidth, m_videoHeight); -+ CServiceBroker::GetDataCacheCore().SetVideoFps(m_videoFPS); - } - - void CProcessInfo::SetVideoDecoderName(std::string name, bool isHw) -@@ -80,7 +81,7 @@ void CProcessInfo::SetVideoDecoderName(std::string name, bool isHw) - m_videoIsHWDecoder = isHw; - m_videoDecoderName = name; - -- g_dataCacheCore.SetVideoDecoderName(m_videoDecoderName, m_videoIsHWDecoder); -+ CServiceBroker::GetDataCacheCore().SetVideoDecoderName(m_videoDecoderName, m_videoIsHWDecoder); - } - - std::string CProcessInfo::GetVideoDecoderName() -@@ -103,7 +104,7 @@ void CProcessInfo::SetVideoDeintMethod(std::string method) - - m_videoDeintMethod = method; - -- g_dataCacheCore.SetVideoDeintMethod(m_videoDeintMethod); -+ CServiceBroker::GetDataCacheCore().SetVideoDeintMethod(m_videoDeintMethod); - } - - std::string CProcessInfo::GetVideoDeintMethod() -@@ -119,7 +120,7 @@ void CProcessInfo::SetVideoPixelFormat(std::string pixFormat) - - m_videoPixelFormat = pixFormat; - -- g_dataCacheCore.SetVideoPixelFormat(m_videoPixelFormat); -+ CServiceBroker::GetDataCacheCore().SetVideoPixelFormat(m_videoPixelFormat); - } - - std::string CProcessInfo::GetVideoPixelFormat() -@@ -136,7 +137,7 @@ void CProcessInfo::SetVideoDimensions(int width, int height) - m_videoWidth = width; - m_videoHeight = height; - -- g_dataCacheCore.SetVideoDimensions(m_videoWidth, m_videoHeight); -+ CServiceBroker::GetDataCacheCore().SetVideoDimensions(m_videoWidth, m_videoHeight); - } - - void CProcessInfo::GetVideoDimensions(int &width, int &height) -@@ -153,7 +154,7 @@ void CProcessInfo::SetVideoFps(float fps) - - m_videoFPS = fps; - -- g_dataCacheCore.SetVideoFps(m_videoFPS); -+ CServiceBroker::GetDataCacheCore().SetVideoFps(m_videoFPS); - } - - float CProcessInfo::GetVideoFps() -@@ -189,10 +190,10 @@ void CProcessInfo::ResetAudioCodecInfo() - m_audioSampleRate = 0;; - m_audioBitsPerSample = 0; - -- g_dataCacheCore.SetAudioDecoderName(m_audioDecoderName); -- g_dataCacheCore.SetAudioChannels(m_audioChannels); -- g_dataCacheCore.SetAudioSampleRate(m_audioSampleRate); -- g_dataCacheCore.SetAudioBitsPerSample(m_audioBitsPerSample); -+ CServiceBroker::GetDataCacheCore().SetAudioDecoderName(m_audioDecoderName); -+ CServiceBroker::GetDataCacheCore().SetAudioChannels(m_audioChannels); -+ CServiceBroker::GetDataCacheCore().SetAudioSampleRate(m_audioSampleRate); -+ CServiceBroker::GetDataCacheCore().SetAudioBitsPerSample(m_audioBitsPerSample); - } - - void CProcessInfo::SetAudioDecoderName(std::string name) -diff --git a/xbmc/cores/VideoPlayer/VideoPlayer.cpp b/xbmc/cores/VideoPlayer/VideoPlayer.cpp -index 9ed9176..5205414 100644 ---- a/xbmc/cores/VideoPlayer/VideoPlayer.cpp -+++ b/xbmc/cores/VideoPlayer/VideoPlayer.cpp -@@ -45,6 +45,7 @@ - #include "guilib/GUIWindowManager.h" - #include "guilib/StereoscopicsManager.h" - #include "Application.h" -+#include "ServiceBroker.h" - #include "messaging/ApplicationMessenger.h" - - #include "DVDDemuxers/DVDDemuxCC.h" -@@ -81,6 +82,7 @@ - #include "cores/omxplayer/OMXHelper.h" - #endif - #include "VideoPlayerAudio.h" -+#include "cores/DataCacheCore.h" - #include "windowing/WindowingFactory.h" - #include "DVDCodecs/DVDCodecUtils.h" - -@@ -545,8 +547,8 @@ void CSelectionStreams::Update(CDVDInputStream* input, CDVDDemux* demuxer, std:: - Update(s); - } - } -- g_dataCacheCore.SignalAudioInfoChange(); -- g_dataCacheCore.SignalVideoInfoChange(); -+ CServiceBroker::GetDataCacheCore().SignalAudioInfoChange(); -+ CServiceBroker::GetDataCacheCore().SignalVideoInfoChange(); - } - - int CSelectionStreams::CountSource(StreamType type, StreamSource source) const -@@ -2872,8 +2874,8 @@ void CVideoPlayer::HandleMessages() - else if (pMsg->IsType(CDVDMsg::PLAYER_AVCHANGE)) - { - UpdateStreamInfos(); -- g_dataCacheCore.SignalAudioInfoChange(); -- g_dataCacheCore.SignalVideoInfoChange(); -+ CServiceBroker::GetDataCacheCore().SignalAudioInfoChange(); -+ CServiceBroker::GetDataCacheCore().SignalVideoInfoChange(); - } - - pMsg->Release(); -@@ -3596,8 +3598,8 @@ bool CVideoPlayer::OpenStream(CCurrentStream& current, int64_t demuxerId, int iS - } - } - -- g_dataCacheCore.SignalAudioInfoChange(); -- g_dataCacheCore.SignalVideoInfoChange(); -+ CServiceBroker::GetDataCacheCore().SignalAudioInfoChange(); -+ CServiceBroker::GetDataCacheCore().SignalVideoInfoChange(); - - return res; - } -diff --git a/xbmc/cores/paplayer/PAPlayer.cpp b/xbmc/cores/paplayer/PAPlayer.cpp -index 17e1cfc..6bd5180 100644 ---- a/xbmc/cores/paplayer/PAPlayer.cpp -+++ b/xbmc/cores/paplayer/PAPlayer.cpp -@@ -21,6 +21,7 @@ - #include "PAPlayer.h" - #include "CodecFactory.h" - #include "FileItem.h" -+#include "ServiceBroker.h" - #include "settings/AdvancedSettings.h" - #include "settings/Settings.h" - #include "music/tags/MusicInfoTag.h" -@@ -1130,7 +1131,7 @@ void PAPlayer::UpdateGUIData(StreamInfo *si) - total -= m_currentStream->m_startOffset; - m_playerGUIData.m_totalTime = total; - -- g_dataCacheCore.SignalAudioInfoChange(); -+ CServiceBroker::GetDataCacheCore().SignalAudioInfoChange(); - } - - void PAPlayer::OnJobComplete(unsigned int jobID, bool success, CJob *job) - -From 0337c933aaf3a438edba894780838f5c1fbb00f5 Mon Sep 17 00:00:00 2001 -From: popcornmix <popcornmix@gmail.com> -Date: Fri, 24 Jun 2016 19:37:32 +0100 -Subject: [PATCH 3/3] rbp: Update to use new processInfo data cache - ---- - .../VideoPlayer/DVDCodecs/Video/MMALCodec.cpp | 19 +++++++++++++++++ - xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp | 3 ++- - xbmc/cores/omxplayer/OMXAudioCodecOMX.h | 4 +++- - xbmc/cores/omxplayer/OMXPlayerAudio.cpp | 24 +++++++++++++++++++--- - xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 10 ++++----- - xbmc/cores/omxplayer/OMXVideo.cpp | 20 +++++++++++++++++- - xbmc/cores/omxplayer/OMXVideo.h | 4 +++- - 7 files changed, 72 insertions(+), 12 deletions(-) - -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -index 3d026cd..51ded6b2 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -@@ -177,6 +177,10 @@ void CMMALVideo::PortSettingsChanged(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *bu - m_decoded_height = m_es_format->es->video.crop.height; - m_decoded_aligned_width = m_es_format->es->video.width; - m_decoded_aligned_height = m_es_format->es->video.height; -+ -+ m_processInfo.SetVideoDimensions(m_decoded_width, m_decoded_height); -+ m_processInfo.SetVideoDAR(m_aspect_ratio); -+ - if (g_advancedSettings.CanLogComponent(LOGVIDEO)) - CLog::Log(LOGDEBUG, "%s::%s format changed: %dx%d (%dx%d) %.2f", CLASSNAME, __func__, m_decoded_width, m_decoded_height, m_decoded_aligned_width, m_decoded_aligned_height, m_aspect_ratio); - } -@@ -360,6 +364,15 @@ bool CMMALVideo::CreateDeinterlace(EINTERLACEMETHOD interlace_method) - bool advanced_deinterlace = interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED || interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED_HALF; - bool half_framerate = interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED_HALF || interlace_method == VS_INTERLACEMETHOD_MMAL_BOB_HALF; - -+ if (advanced_deinterlace && !half_framerate) -+ m_processInfo.SetVideoDeintMethod("adv(x2)"); -+ else if (advanced_deinterlace && half_framerate) -+ m_processInfo.SetVideoDeintMethod("adv(x1)"); -+ else if (!advanced_deinterlace && !half_framerate) -+ m_processInfo.SetVideoDeintMethod("bob(x2)"); -+ else if (!advanced_deinterlace && half_framerate) -+ m_processInfo.SetVideoDeintMethod("bob(x1)"); -+ - MMAL_PARAMETER_IMAGEFX_PARAMETERS_T imfx_param = {{MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS, sizeof(imfx_param)}, - advanced_deinterlace ? MMAL_PARAM_IMAGEFX_DEINTERLACE_ADV : MMAL_PARAM_IMAGEFX_DEINTERLACE_FAST, 4, {3, 0, half_framerate, 1 }}; - -@@ -437,6 +450,8 @@ bool CMMALVideo::DestroyDeinterlace() - if (g_advancedSettings.CanLogComponent(LOGVIDEO)) - CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__); - -+ m_processInfo.SetVideoDeintMethod("none"); -+ - assert(m_deint); - assert(m_dec_output == m_deint->output[0]); - -@@ -526,6 +541,8 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) - if (!CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_USEMMAL) || hints.software) - return false; - -+ m_processInfo.SetVideoDeintMethod("none"); -+ - m_hints = hints; - m_renderer = (CMMALRenderer *)options.m_opaque_pointer; - MMAL_STATUS_T status; -@@ -732,6 +749,8 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) - m_preroll = !m_hints.stills; - m_speed = DVD_PLAYSPEED_NORMAL; - -+ m_processInfo.SetVideoDecoderName(m_pFormatName, true); -+ - return true; - } - -diff --git a/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp b/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp -index 20f706c..d8cef9c 100644 ---- a/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp -+++ b/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp -@@ -33,7 +33,7 @@ - #define AUDIO_DECODE_OUTPUT_BUFFER (32*1024) - static const char rounded_up_channels_shift[] = {0,0,1,2,2,3,3,3,3}; - --COMXAudioCodecOMX::COMXAudioCodecOMX() -+COMXAudioCodecOMX::COMXAudioCodecOMX(CProcessInfo &processInfo) : m_processInfo(processInfo) - { - m_pBufferOutput = NULL; - m_iBufferOutputAlloced = 0; -@@ -134,6 +134,7 @@ bool COMXAudioCodecOMX::Open(CDVDStreamInfo &hints) - - m_iSampleFormat = AV_SAMPLE_FMT_NONE; - m_desiredSampleFormat = m_pCodecContext->sample_fmt == AV_SAMPLE_FMT_S16 ? AV_SAMPLE_FMT_S16 : AV_SAMPLE_FMT_FLTP; -+ m_processInfo.SetAudioDecoderName(m_pCodecContext->codec->name); - return true; - } - -diff --git a/xbmc/cores/omxplayer/OMXAudioCodecOMX.h b/xbmc/cores/omxplayer/OMXAudioCodecOMX.h -index c06a323..3b2a0f3 100644 ---- a/xbmc/cores/omxplayer/OMXAudioCodecOMX.h -+++ b/xbmc/cores/omxplayer/OMXAudioCodecOMX.h -@@ -31,11 +31,12 @@ extern "C" { - - #include "DVDStreamInfo.h" - #include "linux/PlatformDefs.h" -+#include "cores/VideoPlayer/Process/ProcessInfo.h" - - class COMXAudioCodecOMX - { - public: -- COMXAudioCodecOMX(); -+ COMXAudioCodecOMX(CProcessInfo &processInfo); - virtual ~COMXAudioCodecOMX(); - bool Open(CDVDStreamInfo &hints); - void Dispose(); -@@ -52,6 +53,7 @@ class COMXAudioCodecOMX - unsigned int GetFrameSize() { return m_frameSize; } - - protected: -+ CProcessInfo &m_processInfo; - AVCodecContext* m_pCodecContext; - SwrContext* m_pConvert; - enum AVSampleFormat m_iSampleFormat; -diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp -index 6161962..1e5d2b9 100644 ---- a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp -+++ b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp -@@ -43,6 +43,7 @@ - #include "linux/RBP.h" - #include "cores/AudioEngine/AEFactory.h" - #include "cores/DataCacheCore.h" -+#include "ServiceBroker.h" - - #include <algorithm> - #include <iomanip> -@@ -101,7 +102,7 @@ bool OMXPlayerAudio::OpenStream(CDVDStreamInfo &hints) - m_bad_state = false; - - m_processInfo.ResetAudioCodecInfo(); -- COMXAudioCodecOMX *codec = new COMXAudioCodecOMX(); -+ COMXAudioCodecOMX *codec = new COMXAudioCodecOMX(m_processInfo); - - if(!codec || !codec->Open(hints)) - { -@@ -143,7 +144,7 @@ void OMXPlayerAudio::OpenStream(CDVDStreamInfo &hints, COMXAudioCodecOMX *codec) - m_format.m_sampleRate = 0; - m_format.m_channelLayout = 0; - -- g_dataCacheCore.SignalAudioInfoChange(); -+ CServiceBroker::GetDataCacheCore().SignalAudioInfoChange(); - } - - void OMXPlayerAudio::CloseStream(bool bWaitForBuffers) -@@ -188,6 +189,7 @@ bool OMXPlayerAudio::CodecChange() - { - m_hints.channels = m_pAudioCodec->GetChannels(); - m_hints.samplerate = m_pAudioCodec->GetSampleRate(); -+ m_hints.bitspersample = m_pAudioCodec->GetBitsPerSample(); - } - - /* only check bitrate changes on AV_CODEC_ID_DTS, AV_CODEC_ID_AC3, AV_CODEC_ID_EAC3 */ -@@ -204,7 +206,11 @@ bool OMXPlayerAudio::CodecChange() - (!m_passthrough && minor_change) || !m_DecoderOpen) - { - m_hints_current = m_hints; -- g_dataCacheCore.SignalAudioInfoChange(); -+ -+ m_processInfo.SetAudioSampleRate(m_hints.samplerate); -+ m_processInfo.SetAudioBitsPerSample(m_hints.bitspersample); -+ -+ CServiceBroker::GetDataCacheCore().SignalAudioInfoChange(); - return true; - } - -@@ -562,11 +568,23 @@ bool OMXPlayerAudio::OpenDecoder() - - CAEChannelInfo channelMap; - if (m_pAudioCodec && !m_passthrough) -+ { - channelMap = m_pAudioCodec->GetChannelMap(); -+ } - else if (m_passthrough) -+ { - // we just want to get the channel count right to stop OMXAudio.cpp rejecting stream - // the actual layout is not used - channelMap = AE_CH_LAYOUT_5_1; -+ -+ if (m_hints.codec == AV_CODEC_ID_AC3) -+ m_processInfo.SetAudioDecoderName("PT_AC3"); -+ else if (m_hints.codec == AV_CODEC_ID_EAC3) -+ m_processInfo.SetAudioDecoderName("PT_EAC3"); -+ else -+ m_processInfo.SetAudioDecoderName("PT_DTS"); -+ } -+ m_processInfo.SetAudioChannels(channelMap); - bool bAudioRenderOpen = m_omxAudio.Initialize(m_format, m_av_clock, m_hints, channelMap, m_passthrough); - - m_codec_name = ""; -diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -index 0ec7f15..6efd0d5 100644 ---- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -@@ -73,8 +73,7 @@ OMXPlayerVideo::OMXPlayerVideo(OMXClock *av_clock, - : CThread("OMXPlayerVideo") - , IDVDStreamPlayerVideo(processInfo) - , m_messageQueue("video") --, m_omxVideo(renderManager) --, m_codecname("") -+, m_omxVideo(renderManager, processInfo) - , m_messageParent(parent) - , m_renderManager(renderManager) - { -@@ -471,7 +470,7 @@ void OMXPlayerVideo::Process() - - if (m_syncState == IDVDStreamPlayer::SYNC_STARTING && !bRequestDrop && settings_changed) - { -- m_codecname = m_omxVideo.GetDecoderName(); -+ m_processInfo.SetVideoDecoderName(m_omxVideo.GetDecoderName(), true); - m_syncState = IDVDStreamPlayer::SYNC_WAITSYNC; - SStartMsg msg; - msg.player = VideoPlayer_VIDEO; -@@ -548,7 +547,7 @@ bool OMXPlayerVideo::OpenDecoder() - CLog::Log(LOGINFO, "OMXPlayerVideo::OpenDecoder : Video codec %s width %d height %d profile %d fps %f\n", - m_omxVideo.GetDecoderName().c_str() , m_hints.width, m_hints.height, m_hints.profile, m_fFrameRate); - -- m_codecname = m_omxVideo.GetDecoderName(); -+ m_processInfo.SetVideoDecoderName(m_omxVideo.GetDecoderName(), true); - } - - return bVideoDecoderOpen; -@@ -710,7 +709,7 @@ void OMXPlayerVideo::ResolutionUpdateCallBack(uint32_t width, uint32_t height, f - } - - m_processInfo.SetVideoDimensions(width, height); -- m_processInfo.SetVideoAspectRatio(display_aspect); -+ m_processInfo.SetVideoDAR(display_aspect); - - unsigned int iDisplayWidth = width; - unsigned int iDisplayHeight = height; -@@ -722,6 +721,7 @@ void OMXPlayerVideo::ResolutionUpdateCallBack(uint32_t width, uint32_t height, f - iDisplayWidth = (int) (iDisplayHeight * display_aspect); - - m_fFrameRate = DVD_TIME_BASE / CDVDCodecUtils::NormalizeFrameduration((double)DVD_TIME_BASE / framerate); -+ m_processInfo.SetVideoFps(m_fFrameRate); - - CLog::Log(LOGDEBUG,"%s - change configuration. video:%dx%d. framerate: %4.2f. %dx%d format: BYPASS", - __FUNCTION__, video_width, video_height, m_fFrameRate, iDisplayWidth, iDisplayHeight); -diff --git a/xbmc/cores/omxplayer/OMXVideo.cpp b/xbmc/cores/omxplayer/OMXVideo.cpp -index 4c165bf..b2bb0a8 100644 ---- a/xbmc/cores/omxplayer/OMXVideo.cpp -+++ b/xbmc/cores/omxplayer/OMXVideo.cpp -@@ -65,8 +65,9 @@ - - #define MAX_TEXT_LENGTH 1024 - --COMXVideo::COMXVideo(CRenderManager& renderManager) : m_video_codec_name("") -+COMXVideo::COMXVideo(CRenderManager& renderManager, CProcessInfo &processInfo) : m_video_codec_name("") - , m_renderManager(renderManager) -+, m_processInfo(processInfo) - { - m_is_open = false; - m_extradata = NULL; -@@ -244,6 +245,19 @@ bool COMXVideo::PortSettingsChanged(ResolutionUpdateInfo &resinfo) - EINTERLACEMETHOD interlace_method = m_renderManager.AutoInterlaceMethod(CMediaSettings::GetInstance().GetCurrentVideoSettings().m_InterlaceMethod); - bool advanced_deinterlace = interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED || interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED_HALF; - bool half_framerate = interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED_HALF || interlace_method == VS_INTERLACEMETHOD_MMAL_BOB_HALF; -+ -+ if (advanced_deinterlace && !half_framerate) -+ m_processInfo.SetVideoDeintMethod("adv(x2)"); -+ else if (advanced_deinterlace && half_framerate) -+ m_processInfo.SetVideoDeintMethod("adv(x1)"); -+ else if (!advanced_deinterlace && !half_framerate) -+ m_processInfo.SetVideoDeintMethod("bob(x2)"); -+ else if (!advanced_deinterlace && half_framerate) -+ m_processInfo.SetVideoDeintMethod("bob(x1)"); -+ -+ if (!half_framerate) -+ resinfo.framerate *= 2.0f; -+ - if (!advanced_deinterlace) - { - // Image_fx assumed 3 frames of context. simple deinterlace doesn't require this -@@ -280,6 +294,10 @@ bool COMXVideo::PortSettingsChanged(ResolutionUpdateInfo &resinfo) - return false; - } - } -+ else -+ { -+ m_processInfo.SetVideoDeintMethod("none"); -+ } - - if(m_deinterlace) - { -diff --git a/xbmc/cores/omxplayer/OMXVideo.h b/xbmc/cores/omxplayer/OMXVideo.h -index 46e79cb..fd101e7 100644 ---- a/xbmc/cores/omxplayer/OMXVideo.h -+++ b/xbmc/cores/omxplayer/OMXVideo.h -@@ -34,6 +34,7 @@ - #include "threads/CriticalSection.h" - #include "xbmc/rendering/RenderSystem.h" - #include "cores/VideoPlayer/VideoRenderers/RenderManager.h" -+#include "cores/VideoPlayer/Process/ProcessInfo.h" - #include <string> - - #define VIDEO_BUFFERS 60 -@@ -53,7 +54,7 @@ struct ResolutionUpdateInfo { - class COMXVideo - { - public: -- COMXVideo(CRenderManager& renderManager); -+ COMXVideo(CRenderManager& renderManager, CProcessInfo &processInfo); - ~COMXVideo(); - - // Required overrides -@@ -112,6 +113,7 @@ class COMXVideo - OMX_DISPLAYTRANSFORMTYPE m_transform; - bool m_settings_changed; - CRenderManager& m_renderManager; -+ CProcessInfo& m_processInfo; - static bool NaluFormatStartCodes(enum AVCodecID codec, uint8_t *in_extradata, int in_extrasize); - CCriticalSection m_critSection; - }; diff --git a/projects/RPi2/patches/kodi/kodi-001-backport.patch b/projects/RPi2/patches/kodi/kodi-001-backport.patch index 1f88c2f0db..baba26d40c 100644 --- a/projects/RPi2/patches/kodi/kodi-001-backport.patch +++ b/projects/RPi2/patches/kodi/kodi-001-backport.patch @@ -1,7 +1,7 @@ -From 1c8dd52e7185c555335c927aa16102e7b758e54d Mon Sep 17 00:00:00 2001 +From 864954f03895aa990ca985273fef53d962ec0cbf Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Tue, 5 May 2015 17:27:39 +0100 -Subject: [PATCH 01/67] build: Allow installed links to be overwritten +Subject: [PATCH 01/61] build: Allow installed links to be overwritten --- tools/depends/target/Makefile | 72 +++++++++++++++++++-------------------- @@ -137,10 +137,10 @@ index e5cb842d9f61578efe5df95dfa3a938cf5346663..3ddba3cefb1ca785f7a17c72f42aacbb + [ -f $(ADDON_DEPS_DIR)/lib/libm.so ] || ln -sf /usr/lib/$(HOST)/libm.so $(ADDON_DEPS_DIR)/lib/ -From 9e113927dc8591c51d7cebc3e13d97c5db19f1d4 Mon Sep 17 00:00:00 2001 +From fd2ced63da994a66ab5c060880009f5e9bab652d Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Mon, 7 Apr 2014 18:19:32 +0100 -Subject: [PATCH 02/67] [rbp/omxplayer] When opening a stream don't try to +Subject: [PATCH 02/61] [rbp/omxplayer] When opening a stream don't try to update gui so often --- @@ -164,10 +164,10 @@ index 8ea5161637b4e66ddd222859f058521dbc8922b9..811019a39a10acc21b83f0b0c70d5500 dialog->ProcessRenderLoop(false); if (allowCancel && dialog->IsCanceled()) -From 13bfba5171501299fc0d21ef4c5b1407807242e2 Mon Sep 17 00:00:00 2001 +From c8caccf7ae230790e5b81b496d664a331c7fbead Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Sat, 8 Mar 2014 15:36:06 +0000 -Subject: [PATCH 03/67] [hifiberry] Hack: force it to be recognised as IEC958 +Subject: [PATCH 03/61] [hifiberry] Hack: force it to be recognised as IEC958 capable to enable passthrough options --- @@ -190,10 +190,10 @@ index 6a9066b2dbe8d505d636b3638c1d35c7c8a698ed..9c6ac5d4cc9bf21b2d48619cc6fb5d27 info.m_displayName.substr(info.m_displayName.size()-5) == " HDMI") { -From c89b8b2588ffc2fb3022bb2debc09648e66f01d1 Mon Sep 17 00:00:00 2001 +From bf2fbaf79191cbfd18b2b6eff7749d1d28cfdc83 Mon Sep 17 00:00:00 2001 From: Ben Avison <bavison@riscosopen.org> Date: Thu, 1 May 2014 16:28:39 +0100 -Subject: [PATCH 04/67] Improved file buffering in CArchive +Subject: [PATCH 04/61] Improved file buffering in CArchive Even though memcpy is typically inlined by the compiler into byte/word loads and stores (at least for release builds), the frequency with which 1, 2 and 4 @@ -213,10 +213,10 @@ that are probably not powerful enough to be good targets for XBMC). 1 file changed, 16 insertions(+) diff --git a/xbmc/utils/Archive.h b/xbmc/utils/Archive.h -index 6ed0f8fe37950306bb6ac369082dd024f032ab66..8506d9593de4c913a3c1469cf9cec89475d8dd30 100644 +index 23cac2759fb10d532da56fa75c5528c5589e9010..89d31d4db1afa7340ed8cd51a7a9fa7acce53b3a 100644 --- a/xbmc/utils/Archive.h +++ b/xbmc/utils/Archive.h -@@ -154,9 +154,17 @@ protected: +@@ -155,9 +155,17 @@ protected: * than waiting until we attempt to put more data into an already full buffer */ if (m_BufferRemain > size) { @@ -233,8 +233,8 @@ index 6ed0f8fe37950306bb6ac369082dd024f032ab66..8506d9593de4c913a3c1469cf9cec894 + } return *this; } - else -@@ -171,9 +179,17 @@ protected: + +@@ -170,9 +178,17 @@ protected: /* Note, refilling the buffer is deferred until we know we need to read more from it */ if (m_BufferRemain >= size) { @@ -251,12 +251,12 @@ index 6ed0f8fe37950306bb6ac369082dd024f032ab66..8506d9593de4c913a3c1469cf9cec894 + } return *this; } - else + -From afe3081bcf63939850a753200650570d04ed8aaa Mon Sep 17 00:00:00 2001 +From ccdbbe94567517e4cb3bc3904d99893affa5132d Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Sun, 10 Aug 2014 16:45:16 +0100 -Subject: [PATCH 05/67] filesystem: Make support of browsing into archives +Subject: [PATCH 05/61] filesystem: Make support of browsing into archives optional The ability to browse, scan and play content in archives can cause problems on low powered/low memory devices. @@ -275,10 +275,10 @@ We'll let people who don't use archives disable it manually 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po -index f0cfe2bc13ec3f333af83df21d0185448896719b..8860129ce3d4fd3426f6ba65d0c8cb8df18be8b2 100644 +index 26915cb15fdd589d54c11b1582ef18dc71f38bb2..62bd967a284b0b93820ef75bf8d76c3e78ee889d 100644 --- a/addons/resource.language.en_gb/resources/strings.po +++ b/addons/resource.language.en_gb/resources/strings.po -@@ -19131,6 +19131,15 @@ msgstr "" +@@ -19173,6 +19173,15 @@ msgstr "" #: system/settings/rbp.xml msgctxt "#38010" msgid "GPU accelerated" @@ -295,7 +295,7 @@ index f0cfe2bc13ec3f333af83df21d0185448896719b..8860129ce3d4fd3426f6ba65d0c8cb8d #. Setting #38011 "Show All Items entry" diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml -index 806eadf44d73cea70fdbd8b723770a7f828e0633..7e6e52f82fde4c91fdc004c4b4b46e86091bcc87 100644 +index 265f3982ceee40ece6e3c5073a0e92902f482212..cf15fcbdb860608b2658b310614e1cd78cc94a18 100644 --- a/system/settings/rbp.xml +++ b/system/settings/rbp.xml @@ -99,4 +99,15 @@ @@ -315,10 +315,10 @@ index 806eadf44d73cea70fdbd8b723770a7f828e0633..7e6e52f82fde4c91fdc004c4b4b46e86 + </section> </settings> diff --git a/xbmc/Util.cpp b/xbmc/Util.cpp -index b0de1c8f1046e094191f19ecd52334ddc6d1b4d1..446d8df2993423a2f80d88f82fbb7f767b11cf1b 100644 +index f1754ef7343daebd51e6bc892b49fd5c1773cd73..b73ecebb203b11e2e7f1bdc8731fafbaf7f070fa 100644 --- a/xbmc/Util.cpp +++ b/xbmc/Util.cpp -@@ -1773,7 +1773,7 @@ void CUtil::ScanPathsForAssociatedItems(const std::string& videoName, +@@ -1778,7 +1778,7 @@ void CUtil::ScanPathsForAssociatedItems(const std::string& videoName, URIUtils::RemoveExtension(strCandidate); if (StringUtils::StartsWithNoCase(strCandidate, videoName)) { @@ -327,7 +327,7 @@ index b0de1c8f1046e094191f19ecd52334ddc6d1b4d1..446d8df2993423a2f80d88f82fbb7f76 CUtil::ScanArchiveForAssociatedItems(pItem->GetPath(), "", item_exts, associatedFiles); else { -@@ -1783,7 +1783,7 @@ void CUtil::ScanPathsForAssociatedItems(const std::string& videoName, +@@ -1788,7 +1788,7 @@ void CUtil::ScanPathsForAssociatedItems(const std::string& videoName, } else { @@ -366,10 +366,10 @@ index a0fd0a9011e71f4af1535110c696b6ea5c4b37db..688b71a297c7c617c6764bfe6be157d7 { CURL xbtUrl = URIUtils::CreateArchivePath("xbt", url); -From b38f7abd72691bb2eb87892e6619a7eba7ebea77 Mon Sep 17 00:00:00 2001 +From d6eca1347e4e38394f6016def44d98a8fcb0fe61 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Mon, 27 Oct 2014 13:06:57 +0000 -Subject: [PATCH 06/67] [rbp] Make cachemembuffersize default depend on memory +Subject: [PATCH 06/61] [rbp] Make cachemembuffersize default depend on memory size --- @@ -379,7 +379,7 @@ Subject: [PATCH 06/67] [rbp] Make cachemembuffersize default depend on memory 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp -index d101638cc38468c3d9673bc48f6603d414bcb7f5..ddbe27061f8192b7f6c830a4c22652a731537079 100644 +index c417308c210204847f9b2d54250af68f2e4e2ee7..6b06c253644a85ca6a5088b07ca41369e38f21d0 100644 --- a/xbmc/linux/RBP.cpp +++ b/xbmc/linux/RBP.cpp @@ -23,6 +23,7 @@ @@ -433,7 +433,7 @@ index a35a509a91483f13e2cf0e688fc7e9528f254290..fffa5182126159f6dfcf750b21fa0464 void Deinitialize(); int GetArmMem() { return m_arm_mem; } diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp -index e7f13a73e5ce6d5fe9864fe76dccc9d3e1fdbc27..446293308010f3b8cd8d325fa6d0285fcc9f892d 100644 +index 6beebe0c9c11b0bab63e5abbd4aea2d62bb05f0c..03f566d3ee4eab690d2236b7739080269d552511 100644 --- a/xbmc/settings/AdvancedSettings.cpp +++ b/xbmc/settings/AdvancedSettings.cpp @@ -50,6 +50,9 @@ @@ -446,7 +446,7 @@ index e7f13a73e5ce6d5fe9864fe76dccc9d3e1fdbc27..446293308010f3b8cd8d325fa6d0285f using namespace ADDON; using namespace XFILE; -@@ -356,7 +359,12 @@ void CAdvancedSettings::Initialize() +@@ -355,7 +358,12 @@ void CAdvancedSettings::Initialize() m_bPVRAutoScanIconsUserSet = false; m_iPVRNumericChannelSwitchTimeout = 1000; @@ -459,7 +459,7 @@ index e7f13a73e5ce6d5fe9864fe76dccc9d3e1fdbc27..446293308010f3b8cd8d325fa6d0285f m_cacheBufferMode = CACHE_BUFFER_MODE_INTERNET; // Default (buffer all internet streams/filesystems) // the following setting determines the readRate of a player data // as multiply of the default data read rate -@@ -405,7 +413,9 @@ void CAdvancedSettings::Initialize() +@@ -404,7 +412,9 @@ void CAdvancedSettings::Initialize() m_extraLogLevels = 0; m_userAgent = g_sysinfo.GetUserAgent(); @@ -471,10 +471,10 @@ index e7f13a73e5ce6d5fe9864fe76dccc9d3e1fdbc27..446293308010f3b8cd8d325fa6d0285f } -From 444ff3630cfa2ff69f1f41150158175ed7d8a549 Mon Sep 17 00:00:00 2001 +From 76c3457a5abf0177d379ed4054938bb73379cc4d Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Fri, 30 May 2014 14:58:43 +0100 -Subject: [PATCH 07/67] [settings] Experiment: Report DESKTOP resolution in +Subject: [PATCH 07/61] [settings] Experiment: Report DESKTOP resolution in video settings --- @@ -496,10 +496,10 @@ index c1cca7efdd5d119b07308b947c569911f2a9bdc9..e03f3c8ef21ba824c0d707042e5a735a StringUtils::Format("%dx%d%s", resolution->width, resolution->height, ModeFlagsToString(resolution->flags, false).c_str()), -From 03a66653809c1494b57bc1644af53c1c111a4765 Mon Sep 17 00:00:00 2001 +From 645bd37c7f9472f391282c5bee72b4d3378dd979 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Wed, 24 Sep 2014 23:13:52 +0100 -Subject: [PATCH 08/67] [audio] Add settings option to boost centre channel +Subject: [PATCH 08/61] [audio] Add settings option to boost centre channel when downmixing This allows a dB volume increase to be added to centre channel. @@ -517,10 +517,10 @@ Should work with Pi Sink (dvdplayer/paplayer) and omxplayer 5 files changed, 46 insertions(+) diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po -index 8860129ce3d4fd3426f6ba65d0c8cb8df18be8b2..f646446b73b2e8a3a783b2e52b3257c6ad6da2bd 100644 +index 62bd967a284b0b93820ef75bf8d76c3e78ee889d..dd36abb9f58c1ea2c6e5591c1b43f138434aad1c 100644 --- a/addons/resource.language.en_gb/resources/strings.po +++ b/addons/resource.language.en_gb/resources/strings.po -@@ -19305,6 +19305,21 @@ msgstr "" +@@ -19347,6 +19347,21 @@ msgstr "" #empty strings from id 38043 to 38099 @@ -543,10 +543,10 @@ index 8860129ce3d4fd3426f6ba65d0c8cb8df18be8b2..f646446b73b2e8a3a783b2e52b3257c6 #: system/settings/settings.xml msgctxt "#38100" diff --git a/system/settings/settings.xml b/system/settings/settings.xml -index c9d3c9dbe5bc5d41c8eb54babf78f9fe4046dd5c..2fad528a2f7ad57db8476c1879f853b8485d08e4 100644 +index 3ab531e9d4fa6c1305a833ba58aaf2a6c44ce310..f7a0ded4e39f1836c7a7cf19a3160d12a30e1a75 100644 --- a/system/settings/settings.xml +++ b/system/settings/settings.xml -@@ -2261,6 +2261,18 @@ +@@ -2268,6 +2268,18 @@ </dependencies> <control type="toggle" /> </setting> @@ -566,7 +566,7 @@ index c9d3c9dbe5bc5d41c8eb54babf78f9fe4046dd5c..2fad528a2f7ad57db8476c1879f853b8 <requirement>HAS_AE_QUALITY_LEVELS</requirement> <level>2</level> diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp -index 0cef1c58fae68f5a74d9ca31073282eb13abb037..23cd1eb96c2515eb5022f5b0220e67785b8aa4de 100644 +index b0ab84baf510d99ef66af86b88f2b23ea41f4e78..809ca88e64092c4c53045849fe98fd480a69651f 100644 --- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResampleFFMPEG.cpp @@ -20,6 +20,7 @@ @@ -577,7 +577,7 @@ index 0cef1c58fae68f5a74d9ca31073282eb13abb037..23cd1eb96c2515eb5022f5b0220e6778 #include "utils/log.h" extern "C" { -@@ -104,6 +105,12 @@ bool CActiveAEResampleFFMPEG::Init(uint64_t dst_chan_layout, int dst_channels, i +@@ -105,6 +106,12 @@ bool CActiveAEResampleFFMPEG::Init(uint64_t dst_chan_layout, int dst_channels, i { av_opt_set_double(m_pContext, "rematrix_maxval", 1.0, 0); } @@ -625,10 +625,10 @@ index f16b822ed7b4aebe18b5d339b3f71ee66e97c23f..993d4b33a294e88c2c004b7943895ba5 // stereo upmix if (upmix && m_src_channels == 2 && m_dst_channels > 2) -From db58404d482592303a170a3519ed43e552f3034a Mon Sep 17 00:00:00 2001 +From c092967c5512c2632533991f6cc25778ad2cb0af Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Mon, 27 Oct 2014 15:23:51 +0000 -Subject: [PATCH 09/67] [rbp] Default extract thumbnails to false +Subject: [PATCH 09/61] [rbp] Default extract thumbnails to false It can take 80 seconds for a single file on a Pi. It can cause crashes with out-of-memory errors. It genereates a lot of support issues. Best to default to disabled and let users enable it if they must @@ -637,7 +637,7 @@ It genereates a lot of support issues. Best to default to disabled and let users 1 file changed, 6 insertions(+) diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml -index 7e6e52f82fde4c91fdc004c4b4b46e86091bcc87..737ec4e0c7f0feb98a6dd008b53e238c41dde8af 100644 +index cf15fcbdb860608b2658b310614e1cd78cc94a18..770c628a15304856504676af82d46d57c97b86b8 100644 --- a/system/settings/rbp.xml +++ b/system/settings/rbp.xml @@ -43,6 +43,12 @@ @@ -654,10 +654,10 @@ index 7e6e52f82fde4c91fdc004c4b4b46e86091bcc87..737ec4e0c7f0feb98a6dd008b53e238c </category> </section> -From e2a04cad01c0fe85bec84480d05a58fe55f84bb2 Mon Sep 17 00:00:00 2001 +From 880e3ee7b784c9deddb66df4d80927699059c199 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Thu, 27 Nov 2014 16:31:56 +0000 -Subject: [PATCH 10/67] [languageinvoker] Reduce priority of python threads +Subject: [PATCH 10/61] [languageinvoker] Reduce priority of python threads --- xbmc/interfaces/generic/LanguageInvokerThread.cpp | 5 +++++ @@ -680,10 +680,10 @@ index fcdd0633f30cd9595ae6cc4ed293677cdcb1f422..16f0c8916b5e0a9e90973d194cf2ebd1 } -From e34bc9595b6b789d3b13165d7abcec3b25c83bfd Mon Sep 17 00:00:00 2001 +From de8e9ca53ad455e535526f9973fb775fbc349d6e Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Sat, 14 Dec 2013 16:55:05 +0000 -Subject: [PATCH 11/67] logging: Add microsecond timer to log messages +Subject: [PATCH 11/61] logging: Add microsecond timer to log messages --- xbmc/utils/log.cpp | 15 +++++++++++++-- @@ -734,10 +734,10 @@ index 3443f1293d86018830269ed992c90a4e69c0430c..d330320842243df6f5ff256e608dddfa levelNames[logLevel]) + strData; -From 6a9154ceb989a8ca0f2c5f50c6746ade14125267 Mon Sep 17 00:00:00 2001 +From 9ca4200de7da40564dd08b6e1d955df3045f27d3 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Sat, 29 Nov 2014 15:25:16 +0000 -Subject: [PATCH 12/67] [rbp] hack: wait for splash to complete before changing +Subject: [PATCH 12/61] [rbp] hack: wait for splash to complete before changing hdmi mode --- @@ -821,22 +821,22 @@ index ee297700f8583dbb15cbe53baf8c887b36bd2ea0..bbe501d40c5e101f1d0d64b8b59b1928 RENDER_STEREO_MODE stereo_mode = g_graphicsContext.GetStereoMode(); -From 6aa85041e715484b032f9e905db8c65388acfe17 Mon Sep 17 00:00:00 2001 +From c86a562cac08f054425e46f2c814b4f2f0d25a3a Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Thu, 11 Dec 2014 17:00:57 +0000 -Subject: [PATCH 13/67] Fix for UI not showing both extractflags and +Subject: [PATCH 13/61] Fix for UI not showing both extractflags and extractthumb --- - addons/resource.language.en_gb/resources/strings.po | 10 +++++++--- - system/settings/settings.xml | 4 ++-- - 2 files changed, 9 insertions(+), 5 deletions(-) + addons/resource.language.en_gb/resources/strings.po | 9 ++++++--- + system/settings/settings.xml | 4 ++-- + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po -index f646446b73b2e8a3a783b2e52b3257c6ad6da2bd..f1100b4238139b15799ddf1dba86265a1eaa53f3 100644 +index dd36abb9f58c1ea2c6e5591c1b43f138434aad1c..3208dad8988fba4bce7687861037274a42ffd21f 100644 --- a/addons/resource.language.en_gb/resources/strings.po +++ b/addons/resource.language.en_gb/resources/strings.po -@@ -12348,7 +12348,7 @@ msgstr "" +@@ -12385,7 +12385,7 @@ msgstr "" #: system/settings/settings.xml msgctxt "#20433" @@ -845,7 +845,7 @@ index f646446b73b2e8a3a783b2e52b3257c6ad6da2bd..f1100b4238139b15799ddf1dba86265a msgstr "" #: xbmc/dialogs/GUIDialogSmartPlaylistRule.cpp -@@ -16783,7 +16783,7 @@ msgstr "" +@@ -16821,7 +16821,7 @@ msgstr "" #. Description of setting with label #20433 "Extract thumbnails and video information" #: system/settings/settings.xml msgctxt "#36178" @@ -854,7 +854,7 @@ index f646446b73b2e8a3a783b2e52b3257c6ad6da2bd..f1100b4238139b15799ddf1dba86265a msgstr "" #. Description of setting with label #20419 "Replace file names with library titles" -@@ -16795,7 +16795,7 @@ msgstr "" +@@ -16833,7 +16833,7 @@ msgstr "" #. Description of setting with label #20433 "Extract thumbnails and video information" #: system/settings/settings.xml msgctxt "#36180" @@ -863,19 +863,18 @@ index f646446b73b2e8a3a783b2e52b3257c6ad6da2bd..f1100b4238139b15799ddf1dba86265a msgstr "" #: system/settings/settings.xml -@@ -19413,3 +19413,7 @@ msgstr "" - msgctxt "#39003" - msgid "Accelerate h264" +@@ -19480,3 +19480,6 @@ msgctxt "#39007" + msgid "This provides access to where picture sources can be added and otherwise managed." msgstr "" -+ + +msgctxt "#38190" +msgid "Extract thumbnails from video files" +msgstr "" diff --git a/system/settings/settings.xml b/system/settings/settings.xml -index 2fad528a2f7ad57db8476c1879f853b8485d08e4..ca7e8892606782e54d4883c5b2f0e6686b1ae280 100644 +index f7a0ded4e39f1836c7a7cf19a3160d12a30e1a75..88b67c1869246037e81fb3efbe293f9fee37d25e 100644 --- a/system/settings/settings.xml +++ b/system/settings/settings.xml -@@ -919,8 +919,8 @@ +@@ -972,8 +972,8 @@ <default>true</default> <control type="toggle" /> </setting> @@ -887,10 +886,10 @@ index 2fad528a2f7ad57db8476c1879f853b8485d08e4..ca7e8892606782e54d4883c5b2f0e668 <control type="toggle" /> </setting> -From 2900f0dc9fa9b7271efc13dfd219ee62a8737f6c Mon Sep 17 00:00:00 2001 +From 589e105736d4d65fea6812e1346317ed7afe518d Mon Sep 17 00:00:00 2001 From: anaconda <anaconda@menakite.eu> Date: Thu, 11 Sep 2014 21:30:43 +0200 -Subject: [PATCH 14/67] Disable autoscrolling while on screensaver and while +Subject: [PATCH 14/61] Disable autoscrolling while on screensaver and while opening streams. --- @@ -903,10 +902,10 @@ Subject: [PATCH 14/67] Disable autoscrolling while on screensaver and while 6 files changed, 24 insertions(+), 3 deletions(-) diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp -index 39c5731cc13c028212c4776511ea978fa2cb6776..bf2f2d3e73cbc88ab9d89f91baa11f983f36ee10 100644 +index def6ed703b25087c4f61f71acb3fbb5257b8c44b..4fffdfad5296775161989468cb8197f892c204e1 100644 --- a/xbmc/Application.cpp +++ b/xbmc/Application.cpp -@@ -5198,3 +5198,13 @@ bool CApplication::NotifyActionListeners(const CAction &action) const +@@ -5188,3 +5188,13 @@ bool CApplication::NotifyActionListeners(const CAction &action) const return false; } @@ -921,10 +920,10 @@ index 39c5731cc13c028212c4776511ea978fa2cb6776..bf2f2d3e73cbc88ab9d89f91baa11f98 + return onBlackDimScreenSaver || openingStreams; +} diff --git a/xbmc/Application.h b/xbmc/Application.h -index 5d38663767a70875d9459a2f4a65979a203edc7b..1aca9fe67fea8436a15a5e2c07b6558b2bdf3ab7 100644 +index c14f62d54fd4623be82eff2d00097fc2c5615d3c..7126e1b1c73d75ff08a6bc58c5f98d5cba6a6fb1 100644 --- a/xbmc/Application.h +++ b/xbmc/Application.h -@@ -394,6 +394,8 @@ public: +@@ -393,6 +393,8 @@ public: */ void UnregisterActionListener(IActionListener *listener); @@ -1021,10 +1020,10 @@ index d7bc1c5ba6067af9a460589920367288c640a915..ac766293f1c47c7f145cb46f6b152144 if (m_lastRenderTime) m_autoScrollDelayTime += currentTime - m_lastRenderTime; -From 91f06fc770b8d9dee8086ab20a7111dc75664229 Mon Sep 17 00:00:00 2001 +From 6dfdde4dd31580ab361d73b46342ca78c2f1abce Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Sat, 13 Dec 2014 18:35:20 +0000 -Subject: [PATCH 15/67] [demuxer] Avoid memcpy on every demuxer packet +Subject: [PATCH 15/61] [demuxer] Avoid memcpy on every demuxer packet Avoids an unnecessary memcpy on every demuxer packet which for high bitrate videos can be significant. @@ -1035,7 +1034,7 @@ high bitrate videos can be significant. 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -index 0b3643c70a9f0d18ccdbb04619d90f82e3b2f232..b9131402dff3a6d538a188794096bad5784dbb63 100644 +index 929f9879e28d6a496ddf713081dcece2cc773a48..bfdec6ffdb882465bb7a4b9db9bd6561963726de 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp @@ -851,7 +851,7 @@ DemuxPacket* CDVDDemuxFFmpeg::Read() @@ -1124,10 +1123,10 @@ index df0f35bd49c65b302de4ccd110d859e8b881ea5f..b4b591ae4c4dd4fb0b36d4d00fedca96 } catch(...) { -From a1f9425d9d9417c7f83806f41b724554653a1be6 Mon Sep 17 00:00:00 2001 +From 83e6d7254eb884e2aaf47445f58b1e96223c93d2 Mon Sep 17 00:00:00 2001 From: anaconda <anaconda@menakite.eu> Date: Wed, 25 Feb 2015 18:22:21 +0100 -Subject: [PATCH 16/67] Load OSD dialogs on startup. +Subject: [PATCH 16/61] Load OSD dialogs on startup. Fixes skipped frames the first time they're loaded in memory on less powered devices, like a Raspberry Pi, when using DVDPlayer. @@ -1142,12 +1141,12 @@ See http://forum.kodi.tv/showthread.php?tid=211501&pid=1938811#pid1938811 6 files changed, 10 insertions(+), 4 deletions(-) diff --git a/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp b/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp -index 1f72db5b0726434505ee7f52296b909b98a5d133..bb2dd07f8c18e6e72c31feb6273b84b599265e0e 100644 +index 65071639e216a37d7b3cec119f1fe573718f44b6..52966fce668bbd1c58aa7e76feb5a2dbf93b1ab7 100644 --- a/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp +++ b/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp -@@ -50,6 +50,7 @@ CGUIDialogPVRChannelsOSD::CGUIDialogPVRChannelsOSD() : - CGUIDialog(WINDOW_DIALOG_PVR_OSD_CHANNELS, "DialogPVRChannelsOSD.xml"), - Observer() +@@ -49,6 +49,7 @@ using namespace KODI::MESSAGING; + CGUIDialogPVRChannelsOSD::CGUIDialogPVRChannelsOSD() : + CGUIDialog(WINDOW_DIALOG_PVR_OSD_CHANNELS, "DialogPVRChannelsOSD.xml") { + m_loadType = LOAD_ON_GUI_INIT; m_vecItems = new CFileItemList; @@ -1207,10 +1206,10 @@ index e498e1fd476d9ab5300bb00bc39946a22cfd93cb..a6648d016b07e2eb3e52f8d927697cc5 CGUIDialogVideoOSD::~CGUIDialogVideoOSD(void) diff --git a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp -index afbe2032b9b2235cd524263d8a730eb3402eb07f..89f685e5dc791a64dd74fa25356d62bbb74f5b58 100644 +index f9bc12da1aea3ea0926fefff93856cdd4328cb2f..ee6984c469023878b1fad18a29056b114d04fdcc 100644 --- a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp +++ b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp -@@ -66,7 +66,9 @@ +@@ -65,7 +65,9 @@ CGUIDialogVideoSettings::CGUIDialogVideoSettings() : CGUIDialogSettingsManualBase(WINDOW_DIALOG_VIDEO_OSD_SETTINGS, "DialogSettings.xml"), m_viewModeChanged(false) @@ -1222,10 +1221,10 @@ index afbe2032b9b2235cd524263d8a730eb3402eb07f..89f685e5dc791a64dd74fa25356d62bb CGUIDialogVideoSettings::~CGUIDialogVideoSettings() { } -From be39b1d7f8f1c217bb78888b18f2a27acc793031 Mon Sep 17 00:00:00 2001 +From b4180c7279375d6ef4c38535c6fa0b09b9cea66d Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Tue, 14 Apr 2015 20:51:14 +0100 -Subject: [PATCH 17/67] [gui] Also limit GUI updates when in non full-screen +Subject: [PATCH 17/61] [gui] Also limit GUI updates when in non full-screen video mode --- @@ -1233,10 +1232,10 @@ Subject: [PATCH 17/67] [gui] Also limit GUI updates when in non full-screen 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp -index bf2f2d3e73cbc88ab9d89f91baa11f983f36ee10..3ecce5b0ac4c1b9d3c4fc0dd759b31f1600ac7fa 100644 +index 4fffdfad5296775161989468cb8197f892c204e1..a98acfce3442f896250fad8003fb5991d1bf0bdc 100644 --- a/xbmc/Application.cpp +++ b/xbmc/Application.cpp -@@ -2707,7 +2707,7 @@ void CApplication::FrameMove(bool processEvents, bool processGUI) +@@ -2743,7 +2743,7 @@ void CApplication::FrameMove(bool processEvents, bool processGUI) #if defined(TARGET_RASPBERRY_PI) || defined(HAS_IMXVPU) // This code reduces rendering fps of the GUI layer when playing videos in fullscreen mode // it makes only sense on architectures with multiple layers @@ -1245,7 +1244,7 @@ index bf2f2d3e73cbc88ab9d89f91baa11f983f36ee10..3ecce5b0ac4c1b9d3c4fc0dd759b31f1 fps = CSettings::GetInstance().GetInt(CSettings::SETTING_VIDEOPLAYER_LIMITGUIUPDATE); #endif -@@ -2720,6 +2720,8 @@ void CApplication::FrameMove(bool processEvents, bool processGUI) +@@ -2756,6 +2756,8 @@ void CApplication::FrameMove(bool processEvents, bool processGUI) { if (!m_skipGuiRender) g_windowManager.Process(CTimeUtils::GetFrameTime()); @@ -1255,85 +1254,10 @@ index bf2f2d3e73cbc88ab9d89f91baa11f983f36ee10..3ecce5b0ac4c1b9d3c4fc0dd759b31f1 g_windowManager.FrameMove(); } -From 3dea2824fdcfe2448b5b6fd348569c34c5c12f84 Mon Sep 17 00:00:00 2001 -From: popcornmix <popcornmix@gmail.com> -Date: Tue, 21 Apr 2015 14:32:07 +0100 -Subject: [PATCH 18/67] [mmalrenderer] Add sharpness control - ---- - addons/resource.language.en_gb/resources/strings.po | 2 +- - .../VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp | 13 ++++++++++++- - .../VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.h | 1 + - 3 files changed, 14 insertions(+), 2 deletions(-) - -diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po -index f1100b4238139b15799ddf1dba86265a1eaa53f3..085e2a195d2e52ce6bea3ed791bf817f5be23b15 100644 ---- a/addons/resource.language.en_gb/resources/strings.po -+++ b/addons/resource.language.en_gb/resources/strings.po -@@ -8631,7 +8631,7 @@ msgstr "" - - #: xbmc/video/dialogs/GUIDialogVideoSettings.cpp - msgctxt "#16313" --msgid "VDPAU - Sharpness" -+msgid "Sharpness" - msgstr "" - - #: xbmc/video/dialogs/GUIDialogVideoSettings.cpp -diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp -index cd573128fdc7e24b5ecf19730b40ef35d1c67a14..d65857779628debfc85b47b8dd283513edb5a319 100644 ---- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp -+++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp -@@ -237,6 +237,7 @@ CMMALRenderer::CMMALRenderer() : CThread("MMALRenderer") - m_inflight = 0; - m_queue = nullptr; - m_error = 0.0; -+ m_sharpness = -2.0f; - } - - CMMALRenderer::~CMMALRenderer() -@@ -419,6 +420,15 @@ void CMMALRenderer::RenderUpdate(bool clear, DWORD flags, DWORD alpha) - - ManageRenderArea(); - -+ // if sharpness setting has changed, we should update it -+ if (m_sharpness != CMediaSettings::GetInstance().GetCurrentVideoSettings().m_Sharpness) -+ { -+ m_sharpness = CMediaSettings::GetInstance().GetCurrentVideoSettings().m_Sharpness; -+ char command[80], response[80]; -+ sprintf(command, "scaling_sharpness %d", ((int)(50.0f * (m_sharpness + 1.0f) + 0.5f))); -+ vc_gencmd(response, sizeof response, command); -+ } -+ - if (m_format != RENDER_FMT_MMAL) - { - if (g_advancedSettings.CanLogComponent(LOGVIDEO)) -@@ -608,7 +618,8 @@ bool CMMALRenderer::Supports(ERENDERFEATURE feature) - feature == RENDERFEATURE_ZOOM || - feature == RENDERFEATURE_ROTATION || - feature == RENDERFEATURE_VERTICAL_SHIFT || -- feature == RENDERFEATURE_PIXEL_RATIO) -+ feature == RENDERFEATURE_PIXEL_RATIO || -+ feature == RENDERFEATURE_SHARPNESS) - return true; - - return false; -diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.h b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.h -index e2c0223836af4171715a3907a5f7ac2511930f5f..ae0ce625c619910530f0b62ea8921aca0a3a7f63 100644 ---- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.h -+++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.h -@@ -116,6 +116,7 @@ protected: - bool m_StereoInvert; - int m_inflight; - bool m_opaque; -+ float m_sharpness; - AVPixelFormat m_pixfmt; - - CCriticalSection m_sharedSection; - -From 121a372d0e98284ede602670609158fc26f8a5be Mon Sep 17 00:00:00 2001 +From 7a8d7fb1bc28289af5f658441709c03bec33d092 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Tue, 5 May 2015 23:58:06 +0100 -Subject: [PATCH 19/67] [screensaver] Leave GUI contents available for +Subject: [PATCH 18/61] [screensaver] Leave GUI contents available for screensaver --- @@ -1341,10 +1265,10 @@ Subject: [PATCH 19/67] [screensaver] Leave GUI contents available for 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/xbmc/guilib/GUIWindowManager.cpp b/xbmc/guilib/GUIWindowManager.cpp -index 5835280d07f049329b05494cd30744c9c1f7a258..93f646e2b28efca6a4bdebbf458127ab597024eb 100644 +index 82b8b32eee8ab95555bbee462b36bfbf819f39b8..14b51568a959afa5648b844a2a87efbb57b5249a 100644 --- a/xbmc/guilib/GUIWindowManager.cpp +++ b/xbmc/guilib/GUIWindowManager.cpp -@@ -789,7 +789,16 @@ void CGUIWindowManager::ActivateWindow_Internal(int iWindowID, const std::vector +@@ -792,7 +792,16 @@ void CGUIWindowManager::ActivateWindow_Internal(int iWindowID, const std::vector int currentWindow = GetActiveWindow(); CGUIWindow *pWindow = GetWindow(currentWindow); if (pWindow) @@ -1363,10 +1287,10 @@ index 5835280d07f049329b05494cd30744c9c1f7a258..93f646e2b28efca6a4bdebbf458127ab // Add window to the history list (we must do this before we activate it, -From d0dac94c4e36e2c8d60311137194573b49ca3c9a Mon Sep 17 00:00:00 2001 +From 3baa1a6cc514b6ceeed4c10fe72d725395b28a06 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Sat, 6 Jun 2015 18:43:57 +0100 -Subject: [PATCH 20/67] ffmpeg: Automatic switch to software decode for GMC +Subject: [PATCH 19/61] ffmpeg: Automatic switch to software decode for GMC with more than one warp point --- @@ -1458,20 +1382,20 @@ index c3998be2f3a5f1dbde2498be624fa8b48de7339f..dffe2da1dfd09e06c5f15c362f7cbe3c CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" CPPFLAGS="$(CPPFLAGS)" LDFLAGS="$(LDFLAGS)" \ ./configure $(ffmpg_config) diff --git a/tools/depends/target/ffmpeg/autobuild.sh b/tools/depends/target/ffmpeg/autobuild.sh -index 6bbebfca1c7189fec6650932d7292f17af60db62..9c26b239c2b2c1221bed7c4d99c46e909a4a5c5d 100755 +index 6bbebfca1c7189fec6650932d7292f17af60db62..e491c788793fa5df35e4570b54d7606183350376 100755 --- a/tools/depends/target/ffmpeg/autobuild.sh +++ b/tools/depends/target/ffmpeg/autobuild.sh @@ -127,6 +127,8 @@ mkdir -p "ffmpeg-${VERSION}" cd "ffmpeg-${VERSION}" || exit 2 tar --strip-components=1 -xf $MYDIR/${ARCHIVE} -+patch -p1 < ../../0001-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patch ++patch -p1 < ../0001-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patch + CFLAGS="$CFLAGS" CXXFLAGS="$CXXFLAGS" LDFLAGS="$LDFLAGS" \ ./configure --prefix=$FFMPEG_PREFIX \ --extra-version="kodi-${VERSION}" \ diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -index 51ded6b236418b7ff31b15b59e5da1b196f31fc2..c0e553ca060749edff28bcbb880ed3e149b9f751 100644 +index db15051b1638411e65c86de50a5be8f2ecbbd91c..c6f98ded45062617d88571cd70fc6336cfdc32c9 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp @@ -47,6 +47,10 @@ @@ -1485,7 +1409,7 @@ index 51ded6b236418b7ff31b15b59e5da1b196f31fc2..c0e553ca060749edff28bcbb880ed3e1 using namespace KODI::MESSAGING; #define CLASSNAME "CMMALVideoBuffer" -@@ -540,6 +544,8 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) +@@ -367,6 +371,8 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) // we always qualify even if DVDFactoryCodec does this too. if (!CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_USEMMAL) || hints.software) return false; @@ -1495,7 +1419,7 @@ index 51ded6b236418b7ff31b15b59e5da1b196f31fc2..c0e553ca060749edff28bcbb880ed3e1 m_processInfo.SetVideoDeintMethod("none"); diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemux.h b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemux.h -index 23cd50ce4643d32fc8f97bc612e9e911169f32d1..86ac5175b0ff1481571beaf0617471e122ee05a1 100644 +index 03fdf6efa072219d55cac21b7f7923ffc6c00e17..e3a32aebfe59016b43cd7c2b304921b58c44e129 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemux.h +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemux.h @@ -157,6 +157,7 @@ public: @@ -1515,10 +1439,10 @@ index 23cd50ce4643d32fc8f97bc612e9e911169f32d1..86ac5175b0ff1481571beaf0617471e1 class CDemuxStreamAudio : public CDemuxStream diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -index b9131402dff3a6d538a188794096bad5784dbb63..84310bbda6440dd10f9aa0711859f4dc0bb1fd1a 100644 +index bfdec6ffdb882465bb7a4b9db9bd6561963726de..c8ba4f869e844550e47ab9084aad1c59ba10f53a 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -@@ -1310,7 +1310,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) +@@ -1323,7 +1323,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) if (!stereoMode.empty()) st->stereo_mode = stereoMode; @@ -1568,7 +1492,7 @@ index f14170850673ebf746df0acf8f5cf5977feae684..85e402bb4e1ddd61bdb657802cc7347c // AUDIO int channels; diff --git a/xbmc/cores/omxplayer/OMXHelper.cpp b/xbmc/cores/omxplayer/OMXHelper.cpp -index b5db1c4ec03e4b5809a14c541329ee11aa7df04f..344f393cfa2230b21a8dba42ef3cf79ce428dac2 100644 +index f135d423c0ca76fd70e79ae5b7d035f0cb79fc75..d9b576bc46055fdab1c134e5f2c63cd4989d015c 100644 --- a/xbmc/cores/omxplayer/OMXHelper.cpp +++ b/xbmc/cores/omxplayer/OMXHelper.cpp @@ -30,6 +30,10 @@ @@ -1594,10 +1518,10 @@ index b5db1c4ec03e4b5809a14c541329ee11aa7df04f..344f393cfa2230b21a8dba42ef3cf79c else if ((hint.codec == AV_CODEC_ID_VC1 || hint.codec == AV_CODEC_ID_WMV3) && g_RBP.GetCodecWvc1()) supported = true; -From e7ca15df03877b289fcaed9838e49758982ecacf Mon Sep 17 00:00:00 2001 +From 43dc7e2beea8ce8abebc3ae26ac7ac31263949ee Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Thu, 10 Mar 2016 17:56:11 +0000 -Subject: [PATCH 21/67] [rbp] HW mouse pointer +Subject: [PATCH 20/61] [rbp] HW mouse pointer Updating the mouse point provokes a complete screen update which can make it feel laggy and results in high cpu. @@ -1612,10 +1536,10 @@ Render the mouse with an overlay to avoid redrawing the normal gui. 5 files changed, 282 insertions(+) diff --git a/xbmc/guilib/GUIWindowManager.cpp b/xbmc/guilib/GUIWindowManager.cpp -index 93f646e2b28efca6a4bdebbf458127ab597024eb..4bedbdde8c9b226e86a0c37378597bd524dbe66e 100644 +index 14b51568a959afa5648b844a2a87efbb57b5249a..5384f5686578ee455263b0ee636b2adc332e0264 100644 --- a/xbmc/guilib/GUIWindowManager.cpp +++ b/xbmc/guilib/GUIWindowManager.cpp -@@ -198,7 +198,9 @@ void CGUIWindowManager::CreateWindows() +@@ -199,7 +199,9 @@ void CGUIWindowManager::CreateWindows() Add(new CGUIWindowAddonBrowser); Add(new CGUIWindowScreensaverDim); Add(new CGUIWindowDebugInfo); @@ -1626,7 +1550,7 @@ index 93f646e2b28efca6a4bdebbf458127ab597024eb..4bedbdde8c9b226e86a0c37378597bd5 Add(new CGUIDialogProgress); Add(new CGUIDialogExtendedProgressBar); diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp -index ddbe27061f8192b7f6c830a4c22652a731537079..fbffa3a952d920cb41412f00f59d5c1c91f98740 100644 +index 6b06c253644a85ca6a5088b07ca41369e38f21d0..92f20e5174dd6b886cf622460ac68ab5f2fe24b9 100644 --- a/xbmc/linux/RBP.cpp +++ b/xbmc/linux/RBP.cpp @@ -28,6 +28,9 @@ @@ -2030,4400 +1954,10 @@ index 1b1d2f2e60334ed0f3a9964d106957f58e69f1b3..c82ba84625fe3556ff49764d40ceb3ec #endif -From f5e09c6ab9f5544d67f94305998b8a3b13f27b9a Mon Sep 17 00:00:00 2001 -From: popcornmix <popcornmix@gmail.com> -Date: Tue, 10 Feb 2015 16:39:12 +0000 -Subject: [PATCH 22/67] [librtmp] Update to 15-Dec-2015 from - http://stream-recorder.com/forum/customized-rtmpdump-binaries-patch-file-t16103.html - ---- - tools/depends/target/librtmp/Makefile | 5 +- - tools/depends/target/librtmp/Patch.diff | 4066 ++++++++++++++++++++++ - tools/depends/target/librtmp/UpdateToLatest.diff | 257 ++ - tools/depends/target/librtmp/libm.patch | 11 - - 4 files changed, 4326 insertions(+), 13 deletions(-) - create mode 100644 tools/depends/target/librtmp/Patch.diff - create mode 100644 tools/depends/target/librtmp/UpdateToLatest.diff - delete mode 100644 tools/depends/target/librtmp/libm.patch - -diff --git a/tools/depends/target/librtmp/Makefile b/tools/depends/target/librtmp/Makefile -index e78d375b1284957036a549a65b8493582cea82e6..03fee99576ab943c72bfb1f5c5b1ccc88450a63a 100644 ---- a/tools/depends/target/librtmp/Makefile -+++ b/tools/depends/target/librtmp/Makefile -@@ -1,5 +1,5 @@ - include ../../Makefile.include --DEPS= ../../Makefile.include Makefile prefix.patch -+DEPS= ../../Makefile.include Makefile prefix.patch UpdateToLatest.diff Patch.diff - - # lib name, version - LIBNAME=rtmpdump -@@ -27,7 +27,8 @@ $(PLATFORM): $(TARBALLS_LOCATION)/$(ARCHIVE) $(DEPS) - rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) - cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) - cd $(PLATFORM); patch -p0 < ../prefix.patch -- cd $(PLATFORM)/librtmp; patch -p0 < ../../libm.patch -+ cd $(PLATFORM); patch -p1 < ../UpdateToLatest.diff -+ cd $(PLATFORM); patch -p0 < ../Patch.diff - sed -i -e 's|CC=|#CC=|' $(PLATFORM)/librtmp/Makefile - sed -i -e 's|LD=|#LD=|' $(PLATFORM)/librtmp/Makefile - sed -i -e 's|AR=|#AR=|' $(PLATFORM)/librtmp/Makefile -diff --git a/tools/depends/target/librtmp/Patch.diff b/tools/depends/target/librtmp/Patch.diff -new file mode 100644 -index 0000000000000000000000000000000000000000..62c1e990e73f61dd205028c3acae0e57d5953f76 ---- /dev/null -+++ b/tools/depends/target/librtmp/Patch.diff -@@ -0,0 +1,4066 @@ -+diff --git Makefile Makefile -+index a1595a8..9fe7584 100644 -+--- Makefile -++++ Makefile -+@@ -32,7 +32,7 @@ BINDIR=$(DESTDIR)$(bindir) -+ SBINDIR=$(DESTDIR)$(sbindir) -+ MANDIR=$(DESTDIR)$(mandir) -+ -+-LIBS_posix= -++LIBS_posix=-lm -+ LIBS_darwin= -+ LIBS_mingw=-lws2_32 -lwinmm -lgdi32 -+ LIB_RTMP=-Llibrtmp -lrtmp -+diff --git librtmp/Makefile librtmp/Makefile -+index 2c1c790..e367535 100644 -+--- librtmp/Makefile -++++ librtmp/Makefile -+@@ -26,7 +26,7 @@ REQ_GNUTLS=gnutls,hogweed,nettle -+ REQ_OPENSSL=libssl,libcrypto -+ PUB_GNUTLS=-lgmp -+ LIBZ=-lz -+-LIBS_posix= -++LIBS_posix=-lm -+ LIBS_darwin= -+ LIBS_mingw=-lws2_32 -lwinmm -lgdi32 -+ LIB_GNUTLS=-lgnutls -lhogweed -lnettle -lgmp $(LIBZ) -+diff --git librtmp/amf.c librtmp/amf.c -+index 1c5f99f..1310cbe 100644 -+--- librtmp/amf.c -++++ librtmp/amf.c -+@@ -319,6 +319,13 @@ AMFProp_SetName(AMFObjectProperty *prop, AVal *name) -+ prop->p_name = *name; -+ } -+ -++void -++AMFProp_SetString(AMFObjectProperty *prop, AVal *str) -++{ -++ prop->p_type = AMF_STRING; -++ prop->p_vu.p_aval = *str; -++} -++ -+ AMFDataType -+ AMFProp_GetType(AMFObjectProperty *prop) -+ { -+@@ -503,6 +510,9 @@ AMF3Prop_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize, -+ return -1; -+ } -+ -++ if (*pBuffer == AMF3_NULL) -++ bDecodeName = FALSE; -++ -+ /* decode name */ -+ if (bDecodeName) -+ { -+@@ -586,7 +596,7 @@ AMF3Prop_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize, -+ } -+ case AMF3_OBJECT: -+ { -+- int nRes = AMF3_Decode(&prop->p_vu.p_object, pBuffer, nSize, TRUE); -++ int nRes = AMF3_Decode(&prop->p_vu.p_object, pBuffer, nSize, FALSE); -+ if (nRes == -1) -+ return -1; -+ nSize -= nRes; -+@@ -620,6 +630,9 @@ AMFProp_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize, -+ return -1; -+ } -+ -++ if (*pBuffer == AMF_NULL) -++ bDecodeName = FALSE; -++ -+ if (bDecodeName && nSize < 4) -+ { /* at least name (length + at least 1 byte) and 1 byte of data */ -+ RTMP_Log(RTMP_LOGDEBUG, -+@@ -649,9 +662,8 @@ AMFProp_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize, -+ return -1; -+ } -+ -+- nSize--; -+- -+ prop->p_type = *pBuffer++; -++ nSize--; -+ switch (prop->p_type) -+ { -+ case AMF_NUMBER: -+@@ -697,9 +709,13 @@ AMFProp_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize, -+ break; -+ case AMF_REFERENCE: -+ { -+- RTMP_Log(RTMP_LOGERROR, "AMF_REFERENCE not supported!"); -+- return -1; -+- break; -++ RTMP_Log(RTMP_LOGDEBUG, "AMF_REFERENCE is not fully supported!"); -++ if (nSize < 2) -++ return -1; -++ prop->p_type = AMF_NUMBER; -++ prop->p_vu.p_number = AMF_DecodeInt16(pBuffer); -++ nSize -= 2; -++ break; -+ } -+ case AMF_ECMA_ARRAY: -+ { -+@@ -731,13 +747,13 @@ AMFProp_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize, -+ } -+ case AMF_DATE: -+ { -+- RTMP_Log(RTMP_LOGDEBUG, "AMF_DATE"); -+- -+ if (nSize < 10) -+ return -1; -+ -+ prop->p_vu.p_number = AMF_DecodeNumber(pBuffer); -+ prop->p_UTCoffset = AMF_DecodeInt16(pBuffer + 8); -++ RTMP_Log(RTMP_LOGDEBUG, "AMF_DATE: %f, UTC offset: %d", prop->p_vu.p_number, -++ prop->p_UTCoffset); -+ -+ nSize -= 10; -+ break; -+@@ -809,8 +825,8 @@ AMFProp_Dump(AMFObjectProperty *prop) -+ } -+ else -+ { -+- name.av_val = "no-name."; -+- name.av_len = sizeof("no-name.") - 1; -++ name.av_val = "no-name"; -++ name.av_len = sizeof ("no-name") - 1; -+ } -+ if (name.av_len > 18) -+ name.av_len = 18; -+@@ -1021,11 +1037,18 @@ AMF3_Decode(AMFObject *obj, const char *pBuffer, int nSize, int bAMFData) -+ obj->o_props = NULL; -+ if (bAMFData) -+ { -+- if (*pBuffer != AMF3_OBJECT) -+- RTMP_Log(RTMP_LOGERROR, -+- "AMF3 Object encapsulated in AMF stream does not start with AMF3_OBJECT!"); -+- pBuffer++; -+- nSize--; -++ // Decode only if it's an AMF3 object -++ if (*pBuffer == AMF3_OBJECT) -++ { -++ pBuffer++; -++ nSize--; -++ } -++ else -++ { -++ RTMP_Log(RTMP_LOGERROR, "AMF3 Object encapsulated in AMF stream does not start with AMF3_OBJECT!"); -++ pBuffer += nOriginalSize; -++ return nOriginalSize; -++ } -+ } -+ -+ ref = 0; -+@@ -1043,8 +1066,12 @@ AMF3_Decode(AMFObject *obj, const char *pBuffer, int nSize, int bAMFData) -+ { -+ int32_t classRef = (ref >> 1); -+ -+- AMF3ClassDef cd = { {0, 0} -+- }; -++ AMF3ClassDef cd; -++ cd.cd_name.av_len = 0; -++ cd.cd_name.av_val = 0; -++ cd.cd_externalizable = FALSE; -++ cd.cd_dynamic = TRUE; -++ cd.cd_num = 0; -+ AMFObjectProperty prop; -+ -+ if ((classRef & 0x1) == 0) -+@@ -1061,6 +1088,7 @@ AMF3_Decode(AMFObject *obj, const char *pBuffer, int nSize, int bAMFData) -+ cd.cd_dynamic = ((classExtRef >> 1) & 0x1) == 1; -+ -+ cdnum = classExtRef >> 2; -++ cd.cd_num = cdnum; -+ -+ /* class name */ -+ -+@@ -1070,24 +1098,25 @@ AMF3_Decode(AMFObject *obj, const char *pBuffer, int nSize, int bAMFData) -+ -+ /*std::string str = className; */ -+ -+- RTMP_Log(RTMP_LOGDEBUG, -+- "Class name: %s, externalizable: %d, dynamic: %d, classMembers: %d", -+- cd.cd_name.av_val, cd.cd_externalizable, cd.cd_dynamic, -+- cd.cd_num); -++ RTMP_Log(RTMP_LOGDEBUG, "Class name: %.*s, externalizable: %d, dynamic: %d, classMembers: %d", -++ cd.cd_name.av_len, cd.cd_name.av_val, cd.cd_externalizable, cd.cd_dynamic, cd.cd_num); -+ -+ for (i = 0; i < cdnum; i++) -+- { -+- AVal memberName; -+- if (nSize <=0) -++ { -++ AVal memberName = {NULL, 0}; -++ if (nSize <= 0) -+ { -+ invalid: -+ RTMP_Log(RTMP_LOGDEBUG, "%s, invalid class encoding!", -+ __FUNCTION__); -+ return nOriginalSize; -+- } -+- len = AMF3ReadString(pBuffer, &memberName); -+- RTMP_Log(RTMP_LOGDEBUG, "Member: %s", memberName.av_val); -+- AMF3CD_AddProp(&cd, &memberName); -++ } -++ len = AMF3ReadString(pBuffer, &memberName); -++ if (memberName.av_val) -++ { -++ RTMP_Log(RTMP_LOGDEBUG, "Member: %.*s", memberName.av_len, memberName.av_val); -++ AMF3CD_AddProp(&cd, &memberName); -++ } -+ nSize -= len; -+ pBuffer += len; -+ } -+@@ -1118,10 +1147,10 @@ invalid: -+ else -+ { -+ int nRes, i; -+- for (i = 0; i < cd.cd_num; i++) /* non-dynamic */ -+- { -+- if (nSize <=0) -+- goto invalid; -++ for (i = 0; i < cd.cd_num; i++) /* non-dynamic */ -++ { -++ if (nSize <= 0) -++ goto invalid; -+ nRes = AMF3Prop_Decode(&prop, pBuffer, nSize, FALSE); -+ if (nRes == -1) -+ RTMP_Log(RTMP_LOGDEBUG, "%s, failed to decode AMF3 property!", -+@@ -1138,9 +1167,9 @@ invalid: -+ int len = 0; -+ -+ do -+- { -+- if (nSize <=0) -+- goto invalid; -++ { -++ if (nSize <= 0) -++ goto invalid; -+ nRes = AMF3Prop_Decode(&prop, pBuffer, nSize, TRUE); -+ AMF_AddProp(obj, &prop); -+ -+@@ -1154,7 +1183,15 @@ invalid: -+ } -+ RTMP_Log(RTMP_LOGDEBUG, "class object!"); -+ } -+- return nOriginalSize - nSize; -++ -++ /** -++ * In case of switch to AMF3 serialization consume rest of the unprocessed -++ * packet data to make sure it's not later processed as AMF0 data. -++ */ -++ if (bAMFData) -++ return nOriginalSize; -++ else -++ return nOriginalSize - nSize; -+ } -+ -+ int -+@@ -1272,7 +1309,8 @@ AMF3CD_AddProp(AMF3ClassDef *cd, AVal *prop) -+ { -+ if (!(cd->cd_num & 0x0f)) -+ cd->cd_props = realloc(cd->cd_props, (cd->cd_num + 16) * sizeof(AVal)); -+- cd->cd_props[cd->cd_num++] = *prop; -++ if (cd->cd_props) -++ cd->cd_props[cd->cd_num++] = *prop; -+ } -+ -+ AVal * -+diff --git librtmp/handshake.h librtmp/handshake.h -+index 0438486..104af28 100644 -+--- librtmp/handshake.h -++++ librtmp/handshake.h -+@@ -707,7 +707,7 @@ HandShake(RTMP * r, int FP9HandShake) -+ uint32_t uptime; -+ -+ uint8_t clientbuf[RTMP_SIG_SIZE + 4], *clientsig=clientbuf+4; -+- uint8_t serversig[RTMP_SIG_SIZE], client2[RTMP_SIG_SIZE], *reply; -++ uint8_t serversig[RTMP_SIG_SIZE], serversig1[RTMP_SIG_SIZE], client2[RTMP_SIG_SIZE], *reply; -+ uint8_t type; -+ getoff *getdh = NULL, *getdig = NULL; -+ -+@@ -760,7 +760,7 @@ HandShake(RTMP * r, int FP9HandShake) -+ #else -+ ip = (int32_t *)(clientsig+8); -+ for (i = 2; i < RTMP_SIG_SIZE/4; i++) -+- *ip++ = rand(); -++ *ip++ = ((rand() & 0xFFFF) << 16) | (rand() & 0xFFFF); -+ #endif -+ -+ /* set handshake digest */ -+@@ -825,6 +825,8 @@ HandShake(RTMP * r, int FP9HandShake) -+ -+ if (ReadN(r, (char *)serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE) -+ return FALSE; -++ if (ReadN(r, (char *) serversig1, RTMP_SIG_SIZE) != RTMP_SIG_SIZE) -++ return FALSE; -+ -+ /* decode server response */ -+ memcpy(&uptime, serversig, 4); -+@@ -834,7 +836,7 @@ HandShake(RTMP * r, int FP9HandShake) -+ RTMP_Log(RTMP_LOGDEBUG, "%s: FMS Version : %d.%d.%d.%d", __FUNCTION__, serversig[4], -+ serversig[5], serversig[6], serversig[7]); -+ -+- if (FP9HandShake && type == 3 && !serversig[4]) -++ if (FP9HandShake && type == 3 && (!serversig[4] || !serversig1[4])) -+ FP9HandShake = FALSE; -+ -+ #ifdef _DEBUG -+@@ -914,7 +916,7 @@ HandShake(RTMP * r, int FP9HandShake) -+ #else -+ ip = (int32_t *)reply; -+ for (i = 0; i < RTMP_SIG_SIZE/4; i++) -+- *ip++ = rand(); -++ *ip++ = ((rand() & 0xFFFF) << 16) | (rand() & 0xFFFF); -+ #endif -+ /* calculate response now */ -+ signatureResp = reply+RTMP_SIG_SIZE-SHA256_DIGEST_LENGTH; -+@@ -965,16 +967,22 @@ HandShake(RTMP * r, int FP9HandShake) -+ __FUNCTION__); -+ RTMP_LogHex(RTMP_LOGDEBUG, reply, RTMP_SIG_SIZE); -+ #endif -+- if (!WriteN(r, (char *)reply, RTMP_SIG_SIZE)) -+- return FALSE; -+- -+- /* 2nd part of handshake */ -+- if (ReadN(r, (char *)serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE) -+- return FALSE; -++ if (r->Link.CombineConnectPacket) -++ { -++ char *HandshakeResponse = malloc(RTMP_SIG_SIZE); -++ memcpy(HandshakeResponse, (char *) reply, RTMP_SIG_SIZE); -++ r->Link.HandshakeResponse.av_val = HandshakeResponse; -++ r->Link.HandshakeResponse.av_len = RTMP_SIG_SIZE; -++ } -++ else -++ { -++ if (!WriteN(r, (char *) reply, RTMP_SIG_SIZE)) -++ return FALSE; -++ } -+ -+ #ifdef _DEBUG -+ RTMP_Log(RTMP_LOGDEBUG, "%s: 2nd handshake: ", __FUNCTION__); -+- RTMP_LogHex(RTMP_LOGDEBUG, serversig, RTMP_SIG_SIZE); -++ RTMP_LogHex(RTMP_LOGDEBUG, serversig1, RTMP_SIG_SIZE); -+ #endif -+ -+ if (FP9HandShake) -+@@ -982,21 +990,21 @@ HandShake(RTMP * r, int FP9HandShake) -+ uint8_t signature[SHA256_DIGEST_LENGTH]; -+ uint8_t digest[SHA256_DIGEST_LENGTH]; -+ -+- if (serversig[4] == 0 && serversig[5] == 0 && serversig[6] == 0 -+- && serversig[7] == 0) -++ if (serversig1[4] == 0 && serversig1[5] == 0 && serversig1[6] == 0 -++ && serversig1[7] == 0) -+ { -+ RTMP_Log(RTMP_LOGDEBUG, -+ "%s: Wait, did the server just refuse signed authentication?", -+ __FUNCTION__); -+ } -+ RTMP_Log(RTMP_LOGDEBUG, "%s: Server sent signature:", __FUNCTION__); -+- RTMP_LogHex(RTMP_LOGDEBUG, &serversig[RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH], -++ RTMP_LogHex(RTMP_LOGDEBUG, &serversig1[RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH], -+ SHA256_DIGEST_LENGTH); -+ -+ /* verify server response */ -+ HMACsha256(&clientsig[digestPosClient], SHA256_DIGEST_LENGTH, -+ GenuineFMSKey, sizeof(GenuineFMSKey), digest); -+- HMACsha256(serversig, RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH, digest, -++ HMACsha256(serversig1, RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH, digest, -+ SHA256_DIGEST_LENGTH, signature); -+ -+ /* show some information */ -+@@ -1024,7 +1032,7 @@ HandShake(RTMP * r, int FP9HandShake) -+ RTMP_Log(RTMP_LOGDEBUG, "%s: Signature calculated:", __FUNCTION__); -+ RTMP_LogHex(RTMP_LOGDEBUG, signature, SHA256_DIGEST_LENGTH); -+ if (memcmp -+- (signature, &serversig[RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH], -++ (signature, &serversig1[RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH], -+ SHA256_DIGEST_LENGTH) != 0) -+ { -+ RTMP_Log(RTMP_LOGWARNING, "%s: Server not genuine Adobe!", __FUNCTION__); -+@@ -1057,7 +1065,7 @@ HandShake(RTMP * r, int FP9HandShake) -+ } -+ else -+ { -+- if (memcmp(serversig, clientsig, RTMP_SIG_SIZE) != 0) -++ if (memcmp(serversig1, clientsig, RTMP_SIG_SIZE) != 0) -+ { -+ RTMP_Log(RTMP_LOGWARNING, "%s: client signature does not match!", -+ __FUNCTION__); -+@@ -1099,7 +1107,7 @@ SHandShake(RTMP * r) -+ { -+ encrypted = FALSE; -+ } -+- else if (type == 6 || type == 8) -++ else if (type == 6 || type == 8 || type == 9) -+ { -+ offalg = 1; -+ encrypted = TRUE; -+@@ -1148,7 +1156,7 @@ SHandShake(RTMP * r) -+ #else -+ ip = (int32_t *)(serversig+8); -+ for (i = 2; i < RTMP_SIG_SIZE/4; i++) -+- *ip++ = rand(); -++ *ip++ = ((rand() & 0xFFFF) << 16) | (rand() & 0xFFFF); -+ #endif -+ -+ /* set handshake digest */ -+diff --git librtmp/hashswf.c librtmp/hashswf.c -+index 9f4e2c0..01b97e2 100644 -+--- librtmp/hashswf.c -++++ librtmp/hashswf.c -+@@ -70,7 +70,7 @@ extern TLS_CTX RTMP_TLS_ctx; -+ -+ #endif /* CRYPTO */ -+ -+-#define AGENT "Mozilla/5.0" -++#define AGENT "Mozilla/5.0 (Windows NT 5.1; rv:21.0) Gecko/20100101 Firefox/21.0" -+ -+ HTTPResult -+ HTTP_get(struct HTTP_ctx *http, const char *url, HTTP_read_callback *cb) -+@@ -116,6 +116,8 @@ HTTP_get(struct HTTP_ctx *http, const char *url, HTTP_read_callback *cb) -+ -+ host = p1 + 3; -+ path = strchr(host, '/'); -++ if (!path) -++ return HTTPRES_BAD_REQUEST; -+ hlen = path - host; -+ strncpy(hbuf, host, hlen); -+ hbuf[hlen] = '\0'; -+@@ -200,7 +202,7 @@ HTTP_get(struct HTTP_ctx *http, const char *url, HTTP_read_callback *cb) -+ } -+ -+ p1 = strchr(sb.sb_buf, ' '); -+- rc = atoi(p1 + 1); -++ rc = p1 ? atoi(p1 + 1) : 400; -+ http->status = rc; -+ -+ if (rc >= 300) -+@@ -379,13 +381,13 @@ make_unix_time(char *s) -+ if (fmt) -+ { -+ /* Day, DD-MMM-YYYY HH:MM:SS GMT */ -+- time.tm_mday = strtol(n + 1, &n, 0); -++ time.tm_mday = strtol(n + 1, &n, 10); -+ month = n + 1; -+ n = strchr(month, ' '); -+- time.tm_year = strtol(n + 1, &n, 0); -+- time.tm_hour = strtol(n + 1, &n, 0); -+- time.tm_min = strtol(n + 1, &n, 0); -+- time.tm_sec = strtol(n + 1, NULL, 0); -++ time.tm_year = strtol(n + 1, &n, 10); -++ time.tm_hour = strtol(n + 1, &n, 10); -++ time.tm_min = strtol(n + 1, &n, 10); -++ time.tm_sec = strtol(n + 1, NULL, 10); -+ } -+ else -+ { -+@@ -395,11 +397,11 @@ make_unix_time(char *s) -+ n = strchr(month, ' '); -+ while (isspace(*n)) -+ n++; -+- time.tm_mday = strtol(n, &n, 0); -+- time.tm_hour = strtol(n + 1, &n, 0); -+- time.tm_min = strtol(n + 1, &n, 0); -+- time.tm_sec = strtol(n + 1, &n, 0); -+- time.tm_year = strtol(n + 1, NULL, 0); -++ time.tm_mday = strtol(n, &n, 10); -++ time.tm_hour = strtol(n + 1, &n, 10); -++ time.tm_min = strtol(n + 1, &n, 10); -++ time.tm_sec = strtol(n + 1, &n, 10); -++ time.tm_year = strtol(n + 1, NULL, 10); -+ } -+ if (time.tm_year > 100) -+ time.tm_year -= ysub; -+@@ -528,9 +530,11 @@ RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash, -+ -+ if (strncmp(buf, "url: ", 5)) -+ continue; -+- if (strncmp(buf + 5, url, hlen)) -++ if (strncmp(buf + 5, url, strlen(buf + 5) - 1)) -+ continue; -+ r1 = strrchr(buf, '/'); -++ if (!r1) -++ continue; -+ i = strlen(r1); -+ r1[--i] = '\0'; -+ if (strncmp(r1, file, i)) -+@@ -640,7 +644,7 @@ RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash, -+ HMAC_finish(in.ctx, hash, hlen); -+ *size = in.size; -+ -+- fprintf(f, "date: %s\n", date); -++ fprintf(f, "date: %s\n", date[0] ? date : cctim); -+ fprintf(f, "size: %08x\n", in.size); -+ fprintf(f, "hash: "); -+ for (i = 0; i < SHA256_DIGEST_LENGTH; i++) -+diff --git librtmp/log.c librtmp/log.c -+index 1b52000..7564a15 100644 -+--- librtmp/log.c -++++ librtmp/log.c -+@@ -52,8 +52,8 @@ static void rtmp_log_default(int level, const char *format, va_list vl) -+ vsnprintf(str, MAX_PRINT_LEN-1, format, vl); -+ -+ /* Filter out 'no-name' */ -+- if ( RTMP_debuglevel<RTMP_LOGALL && strstr(str, "no-name" ) != NULL ) -+- return; -++ if (RTMP_debuglevel < RTMP_LOGDEBUG && strstr(str, "no-name") != NULL) -++ return; -+ -+ if ( !fmsg ) fmsg = stderr; -+ -+diff --git librtmp/parseurl.c librtmp/parseurl.c -+index 646c70c..a0a83e6 100644 -+--- librtmp/parseurl.c -++++ librtmp/parseurl.c -+@@ -34,6 +34,7 @@ int RTMP_ParseURL(const char *url, int *protocol, AVal *host, unsigned int *port -+ AVal *playpath, AVal *app) -+ { -+ char *p, *end, *col, *ques, *slash; -++ int doubleSlash = FALSE; -+ -+ RTMP_Log(RTMP_LOGDEBUG, "Parsing..."); -+ -+@@ -140,11 +141,19 @@ parsehost: -+ char *slash2, *slash3 = NULL, *slash4 = NULL; -+ int applen, appnamelen; -+ -+- slash2 = strchr(p, '/'); -+- if(slash2) -+- slash3 = strchr(slash2+1, '/'); -+- if(slash3) -+- slash4 = strchr(slash3+1, '/'); -++ if ((slash2 = strstr(p, "//"))) -++ { -++ doubleSlash = TRUE; -++ slash2 += 1; -++ } -++ else -++ { -++ slash2 = strchr(p, '/'); -++ if (slash2) -++ slash3 = strchr(slash2 + 1, '/'); -++ if (slash3) -++ slash4 = strchr(slash3 + 1, '/'); -++ } -+ -+ applen = end-p; /* ondemand, pass all parameters as app */ -+ appnamelen = applen; /* ondemand length */ -+@@ -168,6 +177,8 @@ parsehost: -+ applen = appnamelen; -+ } -+ -++ if (doubleSlash) -++ applen -= 1; -+ app->av_val = p; -+ app->av_len = applen; -+ RTMP_Log(RTMP_LOGDEBUG, "Parsed app : %.*s", applen, p); -+diff --git librtmp/rtmp.c librtmp/rtmp.c -+index ca7db6a..c652cff 100644 -+--- librtmp/rtmp.c -++++ librtmp/rtmp.c -+@@ -28,6 +28,7 @@ -+ #include <string.h> -+ #include <assert.h> -+ #include <time.h> -++#include <math.h> -+ -+ #include "rtmp_sys.h" -+ #include "log.h" -+@@ -68,6 +69,7 @@ TLS_CTX RTMP_TLS_ctx; -+ -+ #define RTMP_SIG_SIZE 1536 -+ #define RTMP_LARGE_HEADER_SIZE 12 -++#define HEX2BIN(a) (((a)&0x40)?((a)&0xf)+9:((a)&0xf)) -+ -+ static const int packetSize[] = { 12, 8, 4, 1 }; -+ -+@@ -108,18 +110,25 @@ typedef enum { -+ RTMPT_OPEN=0, RTMPT_SEND, RTMPT_IDLE, RTMPT_CLOSE -+ } RTMPTCmd; -+ -++static int ConnectSocket(RTMP *r); -+ static int DumpMetaData(AMFObject *obj); -+ static int HandShake(RTMP *r, int FP9HandShake); -+ static int SocksNegotiate(RTMP *r); -+ -++static int SendBytesReceived(RTMP *r); -++static int SendCommand(RTMP *r, char *method, int queue); -+ static int SendConnectPacket(RTMP *r, RTMPPacket *cp); -+ static int SendCheckBW(RTMP *r); -+ static int SendCheckBWResult(RTMP *r, double txn); -+ static int SendDeleteStream(RTMP *r, double dStreamId); -+ static int SendFCSubscribe(RTMP *r, AVal *subscribepath); -++static int SendGetStreamLength(RTMP *r); -++static int SendInvoke(RTMP *r, AVal *command, int queue); -+ static int SendPlay(RTMP *r); -+-static int SendBytesReceived(RTMP *r); -+ static int SendUsherToken(RTMP *r, AVal *usherToken); -++static void TransformRot13(AMFObject *obj, AVal *rindex, AVal *r); -++static void __TeaCrypt(uint32_t *block, uint32_t len, uint32_t *key); -++static AVal TeaEncrypt(AVal *srcData, AVal *srcKey); -+ -+ #if 0 /* unused */ -+ static int SendBGHasStream(RTMP *r, double dId, AVal *playpath); -+@@ -338,10 +347,15 @@ RTMP_Init(RTMP *r) -+ r->m_nClientBW = 2500000; -+ r->m_nClientBW2 = 2; -+ r->m_nServerBW = 2500000; -+- r->m_fAudioCodecs = 3191.0; -++ r->m_fAudioCodecs = 3575.0; -+ r->m_fVideoCodecs = 252.0; -++ r->m_fEncoding = 3.0; -+ r->Link.timeout = 30; -+ r->Link.swfAge = 30; -++ r->Link.CombineConnectPacket = TRUE; -++ r->Link.ConnectPacket = FALSE; -++ r->Link.publishId = 0; -++ r->Link.dynamicPublish = FALSE; -+ } -+ -+ void -+@@ -359,6 +373,8 @@ RTMP_GetDuration(RTMP *r) -+ int -+ RTMP_IsConnected(RTMP *r) -+ { -++ if (r->m_sb.sb_size > 0) -++ return TRUE; -+ return r->m_sb.sb_socket != -1; -+ } -+ -+@@ -445,6 +461,8 @@ RTMP_SetupStream(RTMP *r, -+ AVal *flashVer, -+ AVal *subscribepath, -+ AVal *usherToken, -++ AVal *WeebToken, -++ AVal *ccomm, -+ int dStart, -+ int dStop, int bLiveStream, long int timeout) -+ { -+@@ -467,6 +485,8 @@ RTMP_SetupStream(RTMP *r, -+ RTMP_Log(RTMP_LOGDEBUG, "subscribepath : %s", subscribepath->av_val); -+ if (usherToken && usherToken->av_val) -+ RTMP_Log(RTMP_LOGDEBUG, "NetStream.Authenticate.UsherToken : %s", usherToken->av_val); -++ if (WeebToken && WeebToken->av_val) -++ RTMP_Log(RTMP_LOGDEBUG, "WeebToken: %s", WeebToken->av_val); -+ if (flashVer && flashVer->av_val) -+ RTMP_Log(RTMP_LOGDEBUG, "flashVer : %s", flashVer->av_val); -+ if (dStart > 0) -+@@ -515,6 +535,10 @@ RTMP_SetupStream(RTMP *r, -+ r->Link.subscribepath = *subscribepath; -+ if (usherToken && usherToken->av_len) -+ r->Link.usherToken = *usherToken; -++ if (WeebToken && WeebToken->av_len) -++ r->Link.WeebToken = *WeebToken; -++ if (ccomm && ccomm->av_len) -++ r->Link.ccomm = *ccomm; -+ r->Link.seekTime = dStart; -+ r->Link.stopTime = dStop; -+ if (bLiveStream) -+@@ -572,14 +596,24 @@ static struct urlopt { -+ "Stream is live, no seeking possible" }, -+ { AVC("subscribe"), OFF(Link.subscribepath), OPT_STR, 0, -+ "Stream to subscribe to" }, -+- { AVC("jtv"), OFF(Link.usherToken), OPT_STR, 0, -+- "Justin.tv authentication token" }, -+- { AVC("token"), OFF(Link.token), OPT_STR, 0, -++ { AVC("jtv"), OFF(Link.usherToken), OPT_STR, 0, -++ "Justin.tv authentication token"}, -++ { AVC("weeb"), OFF(Link.WeebToken), OPT_STR, 0, -++ "Weeb.tv authentication token"}, -++ { AVC("token"), OFF(Link.token), OPT_STR, 0, -+ "Key for SecureToken response" }, -++ { AVC("ccommand"), OFF(Link.ccomm), OPT_STR, 0, -++ "Send custom command before play" }, -+ { AVC("swfVfy"), OFF(Link.lFlags), OPT_BOOL, RTMP_LF_SWFV, -+ "Perform SWF Verification" }, -+ { AVC("swfAge"), OFF(Link.swfAge), OPT_INT, 0, -+ "Number of days to use cached SWF hash" }, -++#ifdef CRYPTO -++ { AVC("swfsize"), OFF(Link.swfSize), OPT_INT, 0, -++ "Size of the decompressed SWF file"}, -++ { AVC("swfhash"), OFF(Link.swfHash), OPT_STR, 0, -++ "SHA256 hash of the decompressed SWF file"}, -++#endif -+ { AVC("start"), OFF(Link.seekTime), OPT_INT, 0, -+ "Stream start position in milliseconds" }, -+ { AVC("stop"), OFF(Link.stopTime), OPT_INT, 0, -+@@ -685,6 +719,9 @@ parseAMF(AMFObject *obj, AVal *av, int *depth) -+ case 'O': -+ prop.p_type = AMF_OBJECT; -+ break; -++ case 'Z': -++ prop.p_type = AMF_NULL; -++ break; -+ default: -+ return -1; -+ } -+@@ -722,7 +759,7 @@ int RTMP_SetOpt(RTMP *r, const AVal *opt, AVal *arg) -+ *aptr = *arg; } -+ break; -+ case OPT_INT: { -+- long l = strtol(arg->av_val, NULL, 0); -++ long l = strtol(arg->av_val, NULL, 10); -+ *(int *)v = l; } -+ break; -+ case OPT_BOOL: { -+@@ -767,7 +804,7 @@ int RTMP_SetupURL(RTMP *r, char *url) -+ if (!ret) -+ return ret; -+ r->Link.port = port; -+- r->Link.playpath = r->Link.playpath0; -++ r->Link.playpath = AVcopy(r->Link.playpath0); -+ -+ while (ptr) { -+ *ptr++ = '\0'; -+@@ -844,9 +881,16 @@ int RTMP_SetupURL(RTMP *r, char *url) -+ } -+ -+ #ifdef CRYPTO -+- if ((r->Link.lFlags & RTMP_LF_SWFV) && r->Link.swfUrl.av_len) -+- RTMP_HashSWF(r->Link.swfUrl.av_val, &r->Link.SWFSize, -+- (unsigned char *)r->Link.SWFHash, r->Link.swfAge); -++ RTMP_Log(RTMP_LOGDEBUG, "Khalsa: %d %d %s", r->Link.swfSize, r->Link.swfHash.av_len, r->Link.swfHash.av_val); -++ if (r->Link.swfSize && r->Link.swfHash.av_len) -++ { -++ int i, j = 0; -++ for (i = 0; i < r->Link.swfHash.av_len; i += 2) -++ r->Link.SWFHash[j++] = (HEX2BIN(r->Link.swfHash.av_val[i]) << 4) | HEX2BIN(r->Link.swfHash.av_val[i + 1]); -++ r->Link.SWFSize = (uint32_t) r->Link.swfSize; -++ } -++ else if ((r->Link.lFlags & RTMP_LF_SWFV) && r->Link.swfUrl.av_len) -++ RTMP_HashSWF(r->Link.swfUrl.av_val, &r->Link.SWFSize, (unsigned char *) r->Link.SWFHash, r->Link.swfAge); -+ #endif -+ -+ SocksSetup(r, &r->Link.sockshost); -+@@ -949,6 +993,8 @@ RTMP_Connect0(RTMP *r, struct sockaddr * service) -+ } -+ -+ setsockopt(r->m_sb.sb_socket, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on)); -++ if (r->Link.protocol & RTMP_FEATURE_HTTP) -++ setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof (on)); -+ -+ return TRUE; -+ } -+@@ -1399,41 +1445,96 @@ ReadN(RTMP *r, char *buffer, int n) -+ ptr = buffer; -+ while (n > 0) -+ { -+- int nBytes = 0, nRead; -++ int nBytes = 0, nRead, status = 0, retries = 0; -+ if (r->Link.protocol & RTMP_FEATURE_HTTP) -+ { -+- int refill = 0; -+- while (!r->m_resplen) -+- { -+- int ret; -+- if (r->m_sb.sb_size < 13 || refill) -+- { -+- if (!r->m_unackd) -+- HTTP_Post(r, RTMPT_IDLE, "", 1); -+- if (RTMPSockBuf_Fill(&r->m_sb) < 1) -+- { -+- if (!r->m_sb.sb_timedout) -+- RTMP_Close(r); -+- return 0; -+- } -+- } -+- if ((ret = HTTP_read(r, 0)) == -1) -+- { -+- RTMP_Log(RTMP_LOGDEBUG, "%s, No valid HTTP response found", __FUNCTION__); -+- RTMP_Close(r); -+- return 0; -+- } -+- else if (ret == -2) -++ while (!r->m_resplen) -++ { -++ /* Refill if socket buffer is empty */ -++ if (!r->m_sb.sb_size) -+ { -+- refill = 1; -++ if (retries > 30) -++ { -++ RTMP_Close(r); -++ return 0; -++ } -++ -++ if (!r->m_unackd) -++ { -++ if (retries > 0) -++ { -++ HTTP_Post(r, RTMPT_IDLE, "", 1); -++ r->m_unackd = TRUE; -++ } -++ retries++; -++ -++ if (!r->m_bPlaying) -++ sleep(.25); -++ } -++ -++ RTMP_Log(RTMP_LOGDEBUG, "Trying to fill HTTP buffer, Retries: %d", retries); -++ status = RTMPSockBuf_Fill(&r->m_sb); -++ /* Reconnect socket when closed by some moronic servers after -++ * every HTTP data packet */ -++ if (status < 1) -++ { -++ /* Close connection on connection reset */ -++ if (status == -1) -++ { -++ RTMP_Close(r); -++ return 0; -++ } -++ -++ RTMP_Log(RTMP_LOGDEBUG, "Reconnecting socket, Status: %d", status); -++ if (ConnectSocket(r)) -++ { -++ HTTP_Post(r, RTMPT_IDLE, "", 1); -++ r->m_unackd = TRUE; -++ retries++; -++ } -++ else -++ { -++ RTMP_Close(r); -++ return 0; -++ } -++ } -+ } -+- else -++ -++ RTMP_Log(RTMP_LOGDEBUG, "Trying to read HTTP response, Bytes Available: %d", r->m_sb.sb_size); -++ status = HTTP_read(r, 0); -++ if (status == -1) -+ { -+- refill = 0; -++ RTMP_Log(RTMP_LOGDEBUG, "%s, No valid HTTP response found", __FUNCTION__); -++ RTMP_Close(r); -++ return 0; -+ } -+- } -+- if (r->m_resplen && !r->m_sb.sb_size) -+- RTMPSockBuf_Fill(&r->m_sb); -++ else if (status == -2) -++ { -++ if (RTMPSockBuf_Fill(&r->m_sb) < 1) -++ if (!r->m_sb.sb_timedout) -++ { -++ RTMP_Close(r); -++ return 0; -++ } -++ } -++ else if (status == -3) -++ { -++ RTMP_Close(r); -++ return 0; -++ } -++ else -++ r->m_unackd = FALSE; -++ } -++ -++ /* Refill when there is still some data to be read and socket buffer -++ * is empty */ -++ if (r->m_resplen && (!r->m_sb.sb_size)) -++ { -++ if (RTMPSockBuf_Fill(&r->m_sb) < 1) -++ if (!r->m_sb.sb_timedout) -++ RTMP_Close(r); -++ } -++ -+ avail = r->m_sb.sb_size; -+ if (avail > r->m_resplen) -+ avail = r->m_resplen; -+@@ -1460,10 +1561,11 @@ ReadN(RTMP *r, char *buffer, int n) -+ r->m_sb.sb_size -= nRead; -+ nBytes = nRead; -+ r->m_nBytesIn += nRead; -+- if (r->m_bSendCounter -+- && r->m_nBytesIn > ( r->m_nBytesInSent + r->m_nClientBW / 10)) -+- if (!SendBytesReceived(r)) -+- return FALSE; -++ if (r->m_nBytesIn > 0xF0000000) -++ r->m_nBytesIn -= 0xF0000000; -++ if (r->m_bSendCounter && (r->m_nBytesIn > (r->m_nBytesInSent + r->m_nClientBW / 10))) -++ if (!SendBytesReceived(r)) -++ return FALSE; -+ } -+ /*RTMP_Log(RTMP_LOGDEBUG, "%s: %d bytes\n", __FUNCTION__, nBytes); */ -+ #ifdef _DEBUG -+@@ -1474,7 +1576,8 @@ ReadN(RTMP *r, char *buffer, int n) -+ { -+ RTMP_Log(RTMP_LOGDEBUG, "%s, RTMP socket closed by peer", __FUNCTION__); -+ /*goto again; */ -+- RTMP_Close(r); -++ if (!r->m_sb.sb_timedout) -++ RTMP_Close(r); -+ break; -+ } -+ -+@@ -1499,6 +1602,7 @@ static int -+ WriteN(RTMP *r, const char *buffer, int n) -+ { -+ const char *ptr = buffer; -++ char *ConnectPacket = 0; -+ #ifdef CRYPTO -+ char *encrypted = 0; -+ char buf[RTMP_BUFFER_CACHE_SIZE]; -+@@ -1514,6 +1618,15 @@ WriteN(RTMP *r, const char *buffer, int n) -+ } -+ #endif -+ -++ if (r->Link.ConnectPacket) -++ { -++ char *ConnectPacket = malloc(r->Link.HandshakeResponse.av_len + n); -++ memcpy(ConnectPacket, r->Link.HandshakeResponse.av_val, r->Link.HandshakeResponse.av_len); -++ memcpy(ConnectPacket + r->Link.HandshakeResponse.av_len, ptr, n); -++ ptr = ConnectPacket; -++ n += r->Link.HandshakeResponse.av_len; -++ } -++ -+ while (n > 0) -+ { -+ int nBytes; -+@@ -1550,6 +1663,14 @@ WriteN(RTMP *r, const char *buffer, int n) -+ free(encrypted); -+ #endif -+ -++ if (r->Link.ConnectPacket) -++ { -++ if (r->Link.HandshakeResponse.av_val) -++ free(r->Link.HandshakeResponse.av_val); -++ free(ConnectPacket); -++ r->Link.ConnectPacket = FALSE; -++ } -++ -+ return n == 0; -+ } -+ -+@@ -1579,6 +1700,9 @@ SendConnectPacket(RTMP *r, RTMPPacket *cp) -+ char pbuf[4096], *pend = pbuf + sizeof(pbuf); -+ char *enc; -+ -++ if (r->Link.CombineConnectPacket) -++ r->Link.ConnectPacket = TRUE; -++ -+ if (cp) -+ return RTMP_SendPacket(r, cp, TRUE); -+ -+@@ -1627,7 +1751,7 @@ SendConnectPacket(RTMP *r, RTMPPacket *cp) -+ enc = AMF_EncodeNamedBoolean(enc, pend, &av_fpad, FALSE); -+ if (!enc) -+ return FALSE; -+- enc = AMF_EncodeNamedNumber(enc, pend, &av_capabilities, 15.0); -++ enc = AMF_EncodeNamedNumber(enc, pend, &av_capabilities, 239.0); -+ if (!enc) -+ return FALSE; -+ enc = AMF_EncodeNamedNumber(enc, pend, &av_audioCodecs, r->m_fAudioCodecs); -+@@ -1791,7 +1915,7 @@ SendUsherToken(RTMP *r, AVal *usherToken) -+ packet.m_hasAbsTimestamp = 0; -+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE; -+ -+- RTMP_Log(RTMP_LOGDEBUG, "UsherToken: %s", usherToken->av_val); -++ RTMP_Log(RTMP_LOGDEBUG, "UsherToken: %.*s", usherToken->av_len, usherToken->av_val); -+ enc = packet.m_body; -+ enc = AMF_EncodeString(enc, pend, &av_NetStream_Authenticate_UsherToken); -+ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -+@@ -1934,6 +2058,26 @@ SendPublish(RTMP *r) -+ return RTMP_SendPacket(r, &packet, TRUE); -+ } -+ -++static int -++SendDynamicPublish(RTMP *r, double publishId) -++{ -++ char pbuf[1024], *pend = pbuf + sizeof (pbuf), *enc; -++ AVal av_command, av_publishId; -++ -++ enc = pbuf; -++ enc = AMF_EncodeString(enc, pend, &av_publish); -++ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -++ *enc++ = AMF_NULL; -++ av_publishId.av_val = malloc(128 * sizeof (char)); -++ av_publishId.av_len = sprintf(av_publishId.av_val, "%.0f", publishId); -++ enc = AMF_EncodeString(enc, pend, &av_publishId); -++ enc = AMF_EncodeString(enc, pend, &av_live); -++ av_command.av_val = pbuf; -++ av_command.av_len = enc - pbuf; -++ -++ return SendInvoke(r, &av_command, FALSE); -++} -++ -+ SAVC(deleteStream); -+ -+ static int -+@@ -2097,6 +2241,7 @@ SendBytesReceived(RTMP *r) -+ } -+ -+ SAVC(_checkbw); -++SAVC(checkBandwidth); -+ -+ static int -+ SendCheckBW(RTMP *r) -+@@ -2114,7 +2259,7 @@ SendCheckBW(RTMP *r) -+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE; -+ -+ enc = packet.m_body; -+- enc = AMF_EncodeString(enc, pend, &av__checkbw); -++ enc = AMF_EncodeString(enc, pend, &av_checkBandwidth); -+ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -+ *enc++ = AMF_NULL; -+ -+@@ -2221,10 +2366,8 @@ SendPlay(RTMP *r) -+ enc = AMF_EncodeNumber(enc, pend, -1000.0); -+ else -+ { -+- if (r->Link.seekTime > 0.0) -+- enc = AMF_EncodeNumber(enc, pend, r->Link.seekTime); /* resume from here */ -+- else -+- enc = AMF_EncodeNumber(enc, pend, 0.0); /*-2000.0);*/ /* recorded as default, -2000.0 is not reliable since that freezes the player if the stream is not found */ -++ if (r->Link.seekTime > 0.0 || r->Link.stopTime) -++ enc = AMF_EncodeNumber(enc, pend, r->Link.seekTime); /* resume from here */ -+ } -+ if (!enc) -+ return FALSE; -+@@ -2340,7 +2483,7 @@ RTMP_SendCtrl(RTMP *r, short nType, unsigned int nObject, unsigned int nTime) -+ int nSize; -+ char *buf; -+ -+- RTMP_Log(RTMP_LOGDEBUG, "sending ctrl. type: 0x%04x", (unsigned short)nType); -++ RTMP_Log(RTMP_LOGDEBUG, "sending ctrl, type: 0x%04x", (unsigned short)nType); -+ -+ packet.m_nChannel = 0x02; /* control channel (ping) */ -+ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM; -+@@ -2372,8 +2515,8 @@ RTMP_SendCtrl(RTMP *r, short nType, unsigned int nObject, unsigned int nTime) -+ } -+ else if (nType == 0x1A) -+ { -+- *buf = nObject & 0xff; -+- } -++ *buf = nObject & 0xff; -++ } -+ else -+ { -+ if (nSize > 2) -+@@ -2873,6 +3016,7 @@ PublisherAuth(RTMP *r, AVal *description) -+ #endif -+ -+ -++SAVC(onBWCheck); -+ SAVC(onBWDone); -+ SAVC(onFCSubscribe); -+ SAVC(onFCUnsubscribe); -+@@ -2885,24 +3029,25 @@ SAVC(level); -+ SAVC(description); -+ SAVC(onStatus); -+ SAVC(playlist_ready); -++SAVC(cps); -++SAVC(disneyToken); -++SAVC(getStreamLength); -++SAVC(sendStatus); -++SAVC(verifyClient); -+ static const AVal av_NetStream_Failed = AVC("NetStream.Failed"); -+ static const AVal av_NetStream_Play_Failed = AVC("NetStream.Play.Failed"); -+-static const AVal av_NetStream_Play_StreamNotFound = -+-AVC("NetStream.Play.StreamNotFound"); -+-static const AVal av_NetConnection_Connect_InvalidApp = -+-AVC("NetConnection.Connect.InvalidApp"); -++static const AVal av_NetStream_Play_StreamNotFound = AVC("NetStream.Play.StreamNotFound"); -++static const AVal av_NetConnection_Connect_InvalidApp = AVC("NetConnection.Connect.InvalidApp"); -+ static const AVal av_NetStream_Play_Start = AVC("NetStream.Play.Start"); -+ static const AVal av_NetStream_Play_Complete = AVC("NetStream.Play.Complete"); -+ static const AVal av_NetStream_Play_Stop = AVC("NetStream.Play.Stop"); -+ static const AVal av_NetStream_Seek_Notify = AVC("NetStream.Seek.Notify"); -+ static const AVal av_NetStream_Pause_Notify = AVC("NetStream.Pause.Notify"); -+-static const AVal av_NetStream_Play_PublishNotify = -+-AVC("NetStream.Play.PublishNotify"); -+-static const AVal av_NetStream_Play_UnpublishNotify = -+-AVC("NetStream.Play.UnpublishNotify"); -++static const AVal av_NetStream_Play_PublishNotify = AVC("NetStream.Play.PublishNotify"); -++static const AVal av_NetStream_Play_UnpublishNotify = AVC("NetStream.Play.UnpublishNotify"); -+ static const AVal av_NetStream_Publish_Start = AVC("NetStream.Publish.Start"); -+-static const AVal av_NetConnection_Connect_Rejected = -+-AVC("NetConnection.Connect.Rejected"); -++static const AVal av_NetConnection_Connect_Rejected = AVC("NetConnection.Connect.Rejected"); -++static const AVal av_NetConnection_confStream = AVC("NetConnection.confStream"); -+ -+ /* Returns 0 for OK/Failed/error, 1 for 'Stop or Complete' */ -+ static int -+@@ -2912,6 +3057,11 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize) -+ AVal method; -+ double txn; -+ int ret = 0, nRes; -++ char pbuf[512], *pend = pbuf + sizeof (pbuf), *enc, **params = NULL; -++ char *host = r->Link.hostname.av_len ? r->Link.hostname.av_val : ""; -++ char *pageUrl = r->Link.pageUrl.av_len ? r->Link.pageUrl.av_val : ""; -++ int param_count; -++ AVal av_Command, av_Response; -+ if (body[0] != 0x02) /* make sure it is a string method name we start with */ -+ { -+ RTMP_Log(RTMP_LOGWARNING, "%s, Sanity failed. no string method in invoke packet", -+@@ -2952,7 +3102,14 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize) -+ RTMP_Log(RTMP_LOGDEBUG, "%s, received result for method call <%s>", __FUNCTION__, -+ methodInvoked.av_val); -+ -+- if (AVMATCH(&methodInvoked, &av_connect)) -++ if ((r->Link.dynamicPublish == TRUE) && AVMATCH(&methodInvoked, &r->Link.dynamicCommand)) -++ { -++ r->Link.dynamicPublish = FALSE; -++ r->Link.publishId = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3)); -++ RTMP_Log(RTMP_LOGDEBUG, "server returned dynamic publish id: %.0f", r->Link.publishId); -++ RTMP_SendCreateStream(r); -++ } -++ else if (AVMATCH(&methodInvoked, &av_connect)) -+ { -+ if (r->Link.token.av_len) -+ { -+@@ -2973,46 +3130,360 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize) -+ RTMP_SendServerBW(r); -+ RTMP_SendCtrl(r, 3, 0, 300); -+ } -+- RTMP_SendCreateStream(r); -++ if (r->Link.ccomm.av_len) -++ { -++ param_count = strsplit(r->Link.ccomm.av_val, FALSE, ';', ¶ms); -++ if ((param_count > 1) && (strcasecmp(params[1], "TRUE") == 0)) -++ SendCommand(r, params[0], TRUE); -++ else -++ SendCommand(r, params[0], FALSE); -++ if ((param_count > 2) && (strcasecmp(params[2], "TRUE") == 0)) -++ { -++ RTMP_Log(RTMP_LOGDEBUG, "overriding inbuilt dynamic publish command with -K (ccommand) switch"); -++ r->Link.dynamicPublish = TRUE; -++ r->Link.dynamicCommand.av_val = params[0]; -++ r->Link.dynamicCommand.av_len = strlen(params[0]); -++ } -++ else -++ { -++ RTMP_Log(RTMP_LOGDEBUG, "overriding inbuilt site specific authentication with -K (ccommand) switch"); -++ r->Link.dynamicPublish = FALSE; -++ RTMP_SendCreateStream(r); -++ } -++ } -++ else if (strstr(host, "3dbuzz.com") || strstr(pageUrl, "3dbuzz.com")) -++ { -++ AVal r1, r3; -++ AVal av_r1 = AVC("r1"); -++ AVal av_r3 = AVC("r3"); -++ AVal r1_key = AVC("4V?c6k7Y`(6~rMjp6S6!xT04]8m$g2"); -++ AVal r3_key = AVC("aB`d^+8?9;36]Lw2#rg?PDMcX?lCw2"); -++ TransformRot13(&obj, &av_r1, &r1); -++ TransformRot13(&obj, &av_r3, &r3); -++ if (r1.av_val && r3.av_val) -++ { -++ AVal av_qq = AVC("qq"); -++ AVal av_tos = AVC("http://www.3dbuzz.com/home/tos"); -++ AVal av_warning = AVC("Stream capturing is a violation of our terms, and may result in immediate cancellation of your account without refund"); -++ AVal r1_response; -++ -++ RTMP_Log(RTMP_LOGDEBUG, "3DBuzz SecureToken r1 request - %.*s", r1.av_len, r1.av_val); -++ RTMP_Log(RTMP_LOGDEBUG, "3DBuzz SecureToken r3 request - %.*s", r3.av_len, r3.av_val); -++ DecodeTEA(&r1_key, &r1); -++ DecodeTEA(&r3_key, &r3); -++ r1_response = TeaEncrypt(&av_tos, &r1); -++ RTMP_Log(RTMP_LOGDEBUG, "3DBuzz SecureToken r1 response - %.*s", r1_response.av_len, r1_response.av_val); -++ RTMP_Log(RTMP_LOGDEBUG, "3DBuzz SecureToken r3 response - %.*s", r3.av_len, r3.av_val); -++ -++ enc = pbuf; -++ enc = AMF_EncodeString(enc, pend, &av_qq); -++ enc = AMF_EncodeNumber(enc, pend, 0); -++ *enc++ = AMF_NULL; -++ enc = AMF_EncodeString(enc, pend, &r3); -++ enc = AMF_EncodeString(enc, pend, &av_tos); -++ enc = AMF_EncodeString(enc, pend, &r1_response); -++ enc = AMF_EncodeString(enc, pend, &av_warning); -++ av_Command.av_val = pbuf; -++ av_Command.av_len = enc - pbuf; -++ SendInvoke(r, &av_Command, FALSE); -++ } -+ -+- if (!(r->Link.protocol & RTMP_FEATURE_WRITE)) -+- { -+- /* Authenticate on Justin.tv legacy servers before sending FCSubscribe */ -+- if (r->Link.usherToken.av_len) -+- SendUsherToken(r, &r->Link.usherToken); -+- /* Send the FCSubscribe if live stream or if subscribepath is set */ -+- if (r->Link.subscribepath.av_len) -+- SendFCSubscribe(r, &r->Link.subscribepath); -+- else if (r->Link.lFlags & RTMP_LF_LIVE) -+- SendFCSubscribe(r, &r->Link.playpath); -+- } -+- } -++ RTMP_SendCreateStream(r); -++ } -++ else if (strstr(pageUrl, "cam4")) -++ { -++ AMFObject obj2, response; -++ AMFObjectProperty p; -++ AVal Host, ID, IP, av_ChallengeResponse; -++ AVal av_receiveRTMPResponse = AVC("receiveRTMPResponse"); -++ AVal av_client = AVC("client"); -++ AVal av_result = AVC("result"); -++ char ChallengeResponse[16] = {0}; -++ SAVC(application); -++ SAVC(Host); -++ SAVC(ID); -++ SAVC(IP); -++ -++ AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &obj2); -++ if (RTMP_FindFirstMatchingProperty(&obj2, &av_application, &p)) -++ { -++ RTMP_Log(RTMP_LOGDEBUG, "sending cam4 authentication"); -++ AMFProp_GetObject(&p, &obj2); -++ RTMP_FindFirstMatchingProperty(&obj2, &av_Host, &p); -++ AMFProp_GetString(&p, &Host); -++ RTMP_FindFirstMatchingProperty(&obj2, &av_ID, &p); -++ AMFProp_GetString(&p, &ID); -++ RTMP_FindFirstMatchingProperty(&obj2, &av_IP, &p); -++ AMFProp_GetString(&p, &IP); -++ RTMP_Log(RTMP_LOGDEBUG, "Cam4 Host: %.*s", Host.av_len, Host.av_val); -++ RTMP_Log(RTMP_LOGDEBUG, "Cam4 ID : %.*s", ID.av_len, ID.av_val); -++ RTMP_Log(RTMP_LOGDEBUG, "Cam4 IP : %.*s", IP.av_len, IP.av_val); -++ snprintf(ChallengeResponse, 15, "%d", Host.av_len + ID.av_len + IP.av_len); -++ av_ChallengeResponse.av_val = ChallengeResponse; -++ av_ChallengeResponse.av_len = strlen(av_ChallengeResponse.av_val); -++ AMFProp_SetName(&p, &av_client); -++ AMFProp_SetString(&p, &ID); -++ AMF_AddProp(&response, &p); -++ AMFProp_SetName(&p, &av_result); -++ AMFProp_SetString(&p, &av_ChallengeResponse); -++ AMF_AddProp(&response, &p); -++ -++ enc = pbuf; -++ enc = AMF_EncodeString(enc, pend, &av_receiveRTMPResponse); -++ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -++ *enc++ = AMF_NULL; -++ enc = AMF_Encode(&response, enc, pend); -++ enc = AMF_EncodeBoolean(enc, pend, TRUE); -++ av_Response.av_val = pbuf; -++ av_Response.av_len = enc - pbuf; -++ -++ AMF_Decode(&obj, av_Response.av_val, av_Response.av_len, FALSE); -++ AMF_Dump(&obj); -++ SendInvoke(r, &av_Response, TRUE); -++ } -++ -++ RTMP_SendCreateStream(r); -++ } -++ else if ((strstr(host, "highwebmedia.com") || strstr(pageUrl, "chaturbate.com")) -++ && (!strstr(host, "origin"))) -++ { -++ AVal av_ModelName; -++ SAVC(CheckPublicStatus); -++ -++ if (strlen(pageUrl) > 7) -++ { -++ strsplit(pageUrl + 7, FALSE, '/', ¶ms); -++ av_ModelName.av_val = params[1]; -++ av_ModelName.av_len = strlen(params[1]); -++ -++ enc = pbuf; -++ enc = AMF_EncodeString(enc, pend, &av_CheckPublicStatus); -++ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -++ *enc++ = AMF_NULL; -++ enc = AMF_EncodeString(enc, pend, &av_ModelName); -++ av_Command.av_val = pbuf; -++ av_Command.av_len = enc - pbuf; -++ -++ SendInvoke(r, &av_Command, FALSE); -++ } -++ else -++ { -++ RTMP_Log(RTMP_LOGERROR, "you must specify the pageUrl"); -++ RTMP_Close(r); -++ } -++ } -++ else if (strstr(host, "featve.com") || strstr(pageUrl, "featve.com")) -++ { -++ AVal av_auth = AVC("yes"); -++ SAVC(youCannotPlayMe); -++ -++ enc = pbuf; -++ enc = AMF_EncodeString(enc, pend, &av_youCannotPlayMe); -++ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -++ *enc++ = AMF_NULL; -++ enc = AMF_EncodeString(enc, pend, &av_auth); -++ av_Command.av_val = pbuf; -++ av_Command.av_len = enc - pbuf; -++ SendInvoke(r, &av_Command, FALSE); -++ -++ RTMP_SendCreateStream(r); -++ } -++ else if (strstr(host, "tv-stream.to") || strstr(pageUrl, "tv-stream.to")) -++ { -++ static char auth[] = {'h', 0xC2, 0xA7, '4', 'j', 'h', 'H', '4', '3', 'd'}; -++ AVal av_auth; -++ SAVC(requestAccess); -++ av_auth.av_val = auth; -++ av_auth.av_len = sizeof (auth); -++ -++ enc = pbuf; -++ enc = AMF_EncodeString(enc, pend, &av_requestAccess); -++ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -++ *enc++ = AMF_NULL; -++ enc = AMF_EncodeString(enc, pend, &av_auth); -++ av_Command.av_val = pbuf; -++ av_Command.av_len = enc - pbuf; -++ SendInvoke(r, &av_Command, FALSE); -++ -++ SendCommand(r, "getConnectionCount", FALSE); -++ SendGetStreamLength(r); -++ RTMP_SendCreateStream(r); -++ } -++ else if (r->Link.WeebToken.av_len) -++ { -++ AVal av_Token, av_Username, av_Password; -++ SAVC(determineAccess); -++ -++ param_count = strsplit(r->Link.WeebToken.av_val, FALSE, ';', ¶ms); -++ if (param_count >= 1) -++ { -++ av_Token.av_val = params[0]; -++ av_Token.av_len = strlen(params[0]); -++ } -++ if (param_count >= 2) -++ { -++ av_Username.av_val = params[1]; -++ av_Username.av_len = strlen(params[1]); -++ } -++ if (param_count >= 3) -++ { -++ av_Password.av_val = params[2]; -++ av_Password.av_len = strlen(params[2]); -++ } -++ -++ enc = pbuf; -++ enc = AMF_EncodeString(enc, pend, &av_determineAccess); -++ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -++ *enc++ = AMF_NULL; -++ enc = AMF_EncodeString(enc, pend, &av_Token); -++ enc = AMF_EncodeString(enc, pend, &av_Username); -++ enc = AMF_EncodeString(enc, pend, &av_Password); -++ av_Command.av_val = pbuf; -++ av_Command.av_len = enc - pbuf; -++ -++ RTMP_Log(RTMP_LOGDEBUG, "WeebToken: %s", r->Link.WeebToken.av_val); -++ SendInvoke(r, &av_Command, FALSE); -++ } -++ else if (strstr(host, "wfctv.com") || strstr(pageUrl, "wfctv.com")) -++ { -++ AVal av_auth1 = AVC("zoivid"); -++ AVal av_auth2 = AVC("yePi4jee"); -++ SAVC(stream_login); -++ -++ enc = pbuf; -++ enc = AMF_EncodeString(enc, pend, &av_stream_login); -++ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -++ *enc++ = AMF_NULL; -++ enc = AMF_EncodeString(enc, pend, &av_auth1); -++ enc = AMF_EncodeString(enc, pend, &av_auth2); -++ av_Command.av_val = pbuf; -++ av_Command.av_len = enc - pbuf; -++ SendInvoke(r, &av_Command, FALSE); -++ -++ RTMP_SendCreateStream(r); -++ } -++ else if (strstr(host, "pc3oot.us.to")) -++ { -++ SendCommand(r, "UIUIUINASOWAS", TRUE); -++ SendGetStreamLength(r); -++ RTMP_SendCreateStream(r); -++ } -++ else if (strstr(host, "streamscene.cc") || strstr(pageUrl, "streamscene.cc") -++ || strstr(host, "tsboard.tv") || strstr(pageUrl, "teamstream.in") -++ || strstr(host, "hdstreams.tv") || strstr(pageUrl, "teamstream.to") -++ || strstr(pageUrl, "istreams.to")) -++ { -++ SendCommand(r, "r", FALSE); -++ SendGetStreamLength(r); -++ RTMP_SendCreateStream(r); -++ } -++ else if (strstr(pageUrl, "axcast.com")) -++ { -++ SendCommand(r, "requestData", FALSE); -++ RTMP_SendCreateStream(r); -++ } -++ else if (strstr(pageUrl, "dhmediahosting.com")) -++ { -++ SendCommand(r, "netStreamEnable", FALSE); -++ RTMP_SendCreateStream(r); -++ } -++ else if (strstr(pageUrl, "ezcast.tv")) -++ { -++ SendCommand(r, "iUsteJaSakamCarevataKerka", TRUE); -++ RTMP_SendCreateStream(r); -++ } -++ else if (strstr(pageUrl, "janjua.tv")) -++ { -++ SendCommand(r, "soLagaDaSeStoriAga", TRUE); -++ RTMP_SendCreateStream(r); -++ } -++ else if (strstr(pageUrl, "liveflash.tv")) -++ { -++ char *command = "kaskatijaEkonomista"; -++ r->Link.dynamicPublish = TRUE; -++ r->Link.dynamicCommand.av_val = command; -++ r->Link.dynamicCommand.av_len = strlen(command); -++ SendCommand(r, command, TRUE); -++ } -++ else if (strstr(pageUrl, "mips.tv") || strstr(pageUrl, "mipsplayer.com")) -++ { -++ char *command = "gaolVanusPobeleVoKosata"; -++ r->Link.dynamicPublish = TRUE; -++ r->Link.dynamicCommand.av_val = command; -++ r->Link.dynamicCommand.av_len = strlen(command); -++ SendCommand(r, command, TRUE); -++ } -++ else if (strstr(pageUrl, "streamify.tv")) -++ { -++ SendCommand(r, "keGoVidishStambolSoseBardovci", TRUE); -++ RTMP_SendCreateStream(r); -++ } -++ else if (strstr(pageUrl, "ucaster.eu")) -++ { -++ SendCommand(r, "vujkoMiLazarBarakovOdMonospitovo", TRUE); -++ RTMP_SendCreateStream(r); -++ } -++ else if (strstr(pageUrl, "yukons.net")) -++ { -++ SendCommand(r, "trxuwaaLahRKnaechb", TRUE); -++ RTMP_SendCreateStream(r); -++ } -++ else if (strstr(pageUrl, "yycast.com")) -++ { -++ SendCommand(r, "trajkoProkopiev", TRUE); -++ RTMP_SendCreateStream(r); -++ } -++ else if (strstr(pageUrl, "zenex.tv")) -++ { -++ SendCommand(r, "goVideStambolSoseBardovci", TRUE); -++ RTMP_SendCreateStream(r); -++ } -++ else -++ RTMP_SendCreateStream(r); -++ } -+ else if (AVMATCH(&methodInvoked, &av_createStream)) -+- { -+- r->m_stream_id = (int)AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3)); -++ { -++ r->m_stream_id = (int) AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3)); -+ -+- if (r->Link.protocol & RTMP_FEATURE_WRITE) -+- { -+- SendPublish(r); -+- } -+- else -+- { -+- if (r->Link.lFlags & RTMP_LF_PLST) -+- SendPlaylist(r); -+- SendPlay(r); -+- RTMP_SendCtrl(r, 3, r->m_stream_id, r->m_nBufferMS); -+- } -+- } -++ if (!(r->Link.protocol & RTMP_FEATURE_WRITE)) -++ { -++ /* Authenticate on Justin.tv legacy servers before sending FCSubscribe */ -++ if (r->Link.usherToken.av_len) -++ SendUsherToken(r, &r->Link.usherToken); -++ if (r->Link.publishId > 0) -++ { -++ RTMP_Log(RTMP_LOGDEBUG, "sending dynamic publish id: %.0f", r->Link.publishId); -++ SendDynamicPublish(r, r->Link.publishId); -++ } -++ /* Send the FCSubscribe if live stream or if subscribepath is set */ -++ if (r->Link.subscribepath.av_len) -++ SendFCSubscribe(r, &r->Link.subscribepath); -++ else if ((r->Link.lFlags & RTMP_LF_LIVE) && (!r->Link.WeebToken.av_len)) -++ SendFCSubscribe(r, &r->Link.playpath); -++ } -++ -++ if (r->Link.protocol & RTMP_FEATURE_WRITE) -++ { -++ SendPublish(r); -++ } -++ else -++ { -++ if (r->Link.lFlags & RTMP_LF_PLST) -++ SendPlaylist(r); -++ SendPlay(r); -++ RTMP_SendCtrl(r, 3, r->m_stream_id, r->m_nBufferMS); -++ } -++ } -+ else if (AVMATCH(&methodInvoked, &av_play) || -+- AVMATCH(&methodInvoked, &av_publish)) -+- { -+- r->m_bPlaying = TRUE; -+- } -++ AVMATCH(&methodInvoked, &av_publish)) -++ { -++ r->m_bPlaying = TRUE; -++ } -+ free(methodInvoked.av_val); -+ } -+ else if (AVMATCH(&method, &av_onBWDone)) -+ { -+- if (!r->m_nBWCheckCounter) -++ if (!r->m_nBWCheckCounter) -+ SendCheckBW(r); -+ } -+ else if (AVMATCH(&method, &av_onFCSubscribe)) -+@@ -3036,21 +3507,22 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize) -+ { -+ int i; -+ for (i = 0; i < r->m_numCalls; i++) -+- if (AVMATCH(&r->m_methodCalls[i].name, &av__checkbw)) -+- { -+- AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE); -+- break; -+- } -++ if (AVMATCH(&r->m_methodCalls[i].name, &av__checkbw)) -++ { -++ AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE); -++ break; -++ } -+ } -+ else if (AVMATCH(&method, &av__error)) -+ { -++ int handled = FALSE; -+ #ifdef CRYPTO -+ AVal methodInvoked = {0}; -+ int i; -+ -+ if (r->Link.protocol & RTMP_FEATURE_WRITE) -+ { -+- for (i=0; i<r->m_numCalls; i++) -++ for (i = 0; i < r->m_numCalls; i++) -+ { -+ if (r->m_methodCalls[i].num == txn) -+ { -+@@ -3062,12 +3534,12 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize) -+ if (!methodInvoked.av_val) -+ { -+ RTMP_Log(RTMP_LOGDEBUG, "%s, received result id %f without matching request", -+- __FUNCTION__, txn); -++ __FUNCTION__, txn); -+ goto leave; -+ } -+ -+ RTMP_Log(RTMP_LOGDEBUG, "%s, received error for method call <%s>", __FUNCTION__, -+- methodInvoked.av_val); -++ methodInvoked.av_val); -+ -+ if (AVMATCH(&methodInvoked, &av_connect)) -+ { -+@@ -3086,34 +3558,96 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize) -+ goto leave; -+ } -+ } -+- } -+- else -+- { -+- RTMP_Log(RTMP_LOGERROR, "rtmp server sent error"); -++ handled = TRUE; -+ } -+ free(methodInvoked.av_val); -+-#else -+- RTMP_Log(RTMP_LOGERROR, "rtmp server sent error"); -+ #endif -++ double code = 0.0; -++ unsigned int parsedPort = 0; -++ AMFObject obj2; -++ AMFObjectProperty p; -++ AVal redirect; -++ SAVC(ex); -++ SAVC(redirect); -++ -++ AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &obj2); -++ if (RTMP_FindFirstMatchingProperty(&obj2, &av_ex, &p)) -++ { -++ AMFProp_GetObject(&p, &obj2); -++ if (RTMP_FindFirstMatchingProperty(&obj2, &av_code, &p)) -++ code = AMFProp_GetNumber(&p); -++ if (code == 302 && RTMP_FindFirstMatchingProperty(&obj2, &av_redirect, &p)) -++ { -++ AMFProp_GetString(&p, &redirect); -++ r->Link.redirected = TRUE; -++ -++ char *playpath = "//playpath"; -++ int len = redirect.av_len + strlen(playpath); -++ char *url = malloc(len + 1); -++ memcpy(url, redirect.av_val, redirect.av_len); -++ memcpy(url + redirect.av_len, playpath, strlen(playpath)); -++ url[len] = '\0'; -++ r->Link.tcUrl.av_val = url; -++ r->Link.tcUrl.av_len = redirect.av_len; -++ if (r->Link.lFlags & RTMP_LF_FTCU) -++ r->Link.lFlags ^= RTMP_LF_FTCU; -++ RTMP_ParseURL(url, &r->Link.protocol, &r->Link.hostname, &parsedPort, &r->Link.playpath0, &r->Link.app); -++ if (parsedPort) -++ r->Link.port = parsedPort; -++ } -++ } -++ if (r->Link.redirected) -++ { -++ handled = TRUE; -++ RTMP_Log(RTMP_LOGINFO, "rtmp server sent redirect"); -++ } -++ -++ if (!handled) -++ RTMP_Log(RTMP_LOGERROR, "rtmp server sent error"); -+ } -+ else if (AVMATCH(&method, &av_close)) -+ { -+- RTMP_Log(RTMP_LOGERROR, "rtmp server requested close"); -+- RTMP_Close(r); -++ if (r->Link.redirected) -++ { -++ r->Link.redirected = FALSE; -++ RTMP_Close(r); -++ RTMP_Log(RTMP_LOGINFO, "trying to connect with redirected url"); -++ if (r->Link.port == 0) -++ { -++ if (r->Link.protocol & RTMP_FEATURE_SSL) -++ r->Link.port = 443; -++ else if (r->Link.protocol & RTMP_FEATURE_HTTP) -++ r->Link.port = 80; -++ else -++ r->Link.port = 1935; -++ } -++ RTMP_Connect(r, NULL); -++ } -++ else -++ { -++ -++ RTMP_Log(RTMP_LOGERROR, "rtmp server requested close"); -++ if (r->m_bPlaying && (strstr(pageUrl, "streamlive.to") || strstr(pageUrl, "uk-iptv.co.uk"))) -++ RTMP_Log(RTMP_LOGINFO, "ignoring close request"); -++ else -++ RTMP_Close(r); -++ } -+ } -+ else if (AVMATCH(&method, &av_onStatus)) -+ { -+ AMFObject obj2; -+- AVal code, level; -++ AVal code, level, description; -+ AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &obj2); -+ AMFProp_GetString(AMF_GetProp(&obj2, &av_code, -1), &code); -+ AMFProp_GetString(AMF_GetProp(&obj2, &av_level, -1), &level); -++ AMFProp_GetString(AMF_GetProp(&obj2, &av_description, -1), &description); -+ -+ RTMP_Log(RTMP_LOGDEBUG, "%s, onStatus: %s", __FUNCTION__, code.av_val); -+ if (AVMATCH(&code, &av_NetStream_Failed) -+- || AVMATCH(&code, &av_NetStream_Play_Failed) -+- || AVMATCH(&code, &av_NetStream_Play_StreamNotFound) -+- || AVMATCH(&code, &av_NetConnection_Connect_InvalidApp)) -++ || AVMATCH(&code, &av_NetStream_Play_Failed) -++ || AVMATCH(&code, &av_NetStream_Play_StreamNotFound) -++ || AVMATCH(&code, &av_NetConnection_Connect_Rejected) -++ || AVMATCH(&code, &av_NetConnection_Connect_InvalidApp)) -+ { -+ r->m_stream_id = -1; -+ RTMP_Close(r); -+@@ -3171,6 +3705,46 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize) -+ r->m_pausing = 3; -+ } -+ } -++ -++ else if (AVMATCH(&code, &av_NetConnection_confStream)) -++ { -++#ifdef CRYPTO -++ static const char hexdig[] = "0123456789abcdef"; -++ AVal auth; -++ SAVC(cf_stream); -++ int i; -++ char hash_hex[33] = {0}; -++ unsigned char hash[16]; -++ -++ param_count = strsplit(description.av_val, description.av_len, ':', ¶ms); -++ if (param_count >= 3) -++ { -++ char *buf = malloc(strlen(params[0]) + r->Link.playpath.av_len + 1); -++ strcpy(buf, params[0]); -++ strncat(buf, r->Link.playpath.av_val, r->Link.playpath.av_len); -++ md5_hash((unsigned char *) buf, strlen(buf), hash); -++ for (i = 0; i < 16; i++) -++ { -++ hash_hex[i * 2] = hexdig[0x0f & (hash[i] >> 4)]; -++ hash_hex[i * 2 + 1] = hexdig[0x0f & (hash[i])]; -++ } -++ auth.av_val = &hash_hex[atoi(params[1]) - 1]; -++ auth.av_len = atoi(params[2]); -++ RTMP_Log(RTMP_LOGDEBUG, "Khalsa: %.*s", auth.av_len, auth.av_val); -++ -++ enc = pbuf; -++ enc = AMF_EncodeString(enc, pend, &av_cf_stream); -++ enc = AMF_EncodeNumber(enc, pend, txn); -++ *enc++ = AMF_NULL; -++ enc = AMF_EncodeString(enc, pend, &auth); -++ av_Command.av_val = pbuf; -++ av_Command.av_len = enc - pbuf; -++ -++ SendInvoke(r, &av_Command, FALSE); -++ free(buf); -++ } -++#endif -++ } -+ } -+ else if (AVMATCH(&method, &av_playlist_ready)) -+ { -+@@ -3184,6 +3758,109 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize) -+ } -+ } -+ } -++ else if (AVMATCH(&method, &av_cps)) -++ { -++ if (obj.o_num >= 4) -++ { -++ int Status = AMFProp_GetBoolean(AMF_GetProp(&obj, NULL, 3)); -++ if (Status == FALSE) -++ { -++ AVal Message; -++ AMFProp_GetString(AMF_GetProp(&obj, NULL, 4), &Message); -++ RTMP_Log(RTMP_LOGINFO, "Model status is %.*s", Message.av_len, Message.av_val); -++ RTMP_Close(r); -++ } -++ else -++ { -++ if (obj.o_num >= 7) -++ { -++ AVal Playpath, Server; -++ AMFProp_GetString(AMF_GetProp(&obj, NULL, 5), &Playpath); -++ AMFProp_GetString(AMF_GetProp(&obj, NULL, 6), &Server); -++ if (strncasecmp(&Playpath.av_val[Playpath.av_len - 4], ".mp4", 4) != 0) -++ { -++ char *playpath = calloc(Server.av_len + Playpath.av_len + 25, sizeof (char)); -++ strcat(playpath, "rtmp://"); -++ strncat(playpath, Server.av_val, Server.av_len); -++ strcat(playpath, "/live-origin/"); -++ strncat(playpath, Playpath.av_val, Playpath.av_len); -++ strcat(playpath, ".mp4"); -++ Playpath.av_val = playpath; -++ Playpath.av_len = strlen(playpath); -++ } -++ RTMP_ParsePlaypath(&Playpath, &r->Link.playpath); -++ RTMP_SendCreateStream(r); -++ } -++ } -++ } -++ } -++ else if (AVMATCH(&method, &av_disneyToken)) -++ { -++ double FirstNumber = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3)); -++ double SecondNumber = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 4)); -++ RTMP_Log(RTMP_LOGDEBUG, "FirstNumber: %.2f, SecondNumber: %.2f", FirstNumber, SecondNumber); -++ -++ enc = pbuf; -++ enc = AMF_EncodeString(enc, pend, &av__result); -++ enc = AMF_EncodeNumber(enc, pend, txn); -++ *enc++ = AMF_NULL; -++ enc = AMF_EncodeNumber(enc, pend, FirstNumber * SecondNumber); -++ av_Response.av_val = pbuf; -++ av_Response.av_len = enc - pbuf; -++ -++ AMF_Decode(&obj, av_Response.av_val, av_Response.av_len, FALSE); -++ AMF_Dump(&obj); -++ SendInvoke(r, &av_Response, FALSE); -++ } -++ else if (AVMATCH(&method, &av_verifyClient)) -++ { -++ double VerificationNumber = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3)); -++ RTMP_Log(RTMP_LOGDEBUG, "VerificationNumber: %.2f", VerificationNumber); -++ -++ enc = pbuf; -++ enc = AMF_EncodeString(enc, pend, &av__result); -++ enc = AMF_EncodeNumber(enc, pend, txn); -++ *enc++ = AMF_NULL; -++ enc = AMF_EncodeNumber(enc, pend, exp(atan(sqrt(VerificationNumber))) + 1); -++ av_Response.av_val = pbuf; -++ av_Response.av_len = enc - pbuf; -++ -++ AMF_Decode(&obj, av_Response.av_val, av_Response.av_len, FALSE); -++ AMF_Dump(&obj); -++ SendInvoke(r, &av_Response, FALSE); -++ } -++ else if (AVMATCH(&method, &av_sendStatus)) -++ { -++ if (r->Link.WeebToken.av_len) -++ { -++ AVal av_Authorized = AVC("User.hasAccess"); -++ AVal av_TransferLimit = AVC("User.noPremium.limited"); -++ AVal av_UserLimit = AVC("User.noPremium.tooManyUsers"); -++ AVal av_TimeLeft = AVC("timeLeft"); -++ AVal av_Status, av_ReconnectionTime; -++ -++ AMFObject Status; -++ AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &Status); -++ AMFProp_GetString(AMF_GetProp(&Status, &av_code, -1), &av_Status); -++ RTMP_Log(RTMP_LOGINFO, "%.*s", av_Status.av_len, av_Status.av_val); -++ if (AVMATCH(&av_Status, &av_Authorized)) -++ { -++ RTMP_Log(RTMP_LOGINFO, "Weeb.tv authentication successful"); -++ RTMP_SendCreateStream(r); -++ } -++ else if (AVMATCH(&av_Status, &av_UserLimit)) -++ { -++ RTMP_Log(RTMP_LOGINFO, "No free slots available"); -++ RTMP_Close(r); -++ } -++ else if (AVMATCH(&av_Status, &av_TransferLimit)) -++ { -++ AMFProp_GetString(AMF_GetProp(&Status, &av_TimeLeft, -1), &av_ReconnectionTime); -++ RTMP_Log(RTMP_LOGINFO, "Viewing limit exceeded. try again in %.*s minutes.", av_ReconnectionTime.av_len, av_ReconnectionTime.av_val); -++ RTMP_Close(r); -++ } -++ } -++ } -+ else -+ { -+ -+@@ -3209,7 +3886,8 @@ RTMP_FindFirstMatchingProperty(AMFObject *obj, const AVal *name, -+ return TRUE; -+ } -+ -+- if (prop->p_type == AMF_OBJECT || prop->p_type == AMF_ECMA_ARRAY) -++ if (prop->p_type == AMF_OBJECT || prop->p_type == AMF_ECMA_ARRAY -++ || prop->p_type == AMF_STRICT_ARRAY) -+ { -+ if (RTMP_FindFirstMatchingProperty(&prop->p_vu.p_object, name, p)) -+ return TRUE; -+@@ -3235,7 +3913,8 @@ RTMP_FindPrefixProperty(AMFObject *obj, const AVal *name, -+ return TRUE; -+ } -+ -+- if (prop->p_type == AMF_OBJECT) -++ if (prop->p_type == AMF_OBJECT || prop->p_type == AMF_ECMA_ARRAY -++ || prop->p_type == AMF_STRICT_ARRAY) -+ { -+ if (RTMP_FindPrefixProperty(&prop->p_vu.p_object, name, p)) -+ return TRUE; -+@@ -3269,6 +3948,7 @@ DumpMetaData(AMFObject *obj) -+ snprintf(str, 255, "%s", -+ prop->p_vu.p_number != 0. ? "TRUE" : "FALSE"); -+ break; -++ case AMF_NULL: -+ case AMF_STRING: -+ len = snprintf(str, 255, "%.*s", prop->p_vu.p_aval.av_len, -+ prop->p_vu.p_aval.av_val); -+@@ -3284,7 +3964,7 @@ DumpMetaData(AMFObject *obj) -+ } -+ if (str[0] && prop->p_name.av_len) -+ { -+- RTMP_Log(RTMP_LOGINFO, " %-22.*s%s", prop->p_name.av_len, -++ RTMP_Log(RTMP_LOGINFO, " %-24.*s%s", prop->p_name.av_len, -+ prop->p_name.av_val, str); -+ } -+ } -+@@ -3366,7 +4046,7 @@ HandleCtrl(RTMP *r, const RTMPPacket *packet) -+ unsigned int tmp; -+ if (packet->m_body && packet->m_nBodySize >= 2) -+ nType = AMF_DecodeInt16(packet->m_body); -+- RTMP_Log(RTMP_LOGDEBUG, "%s, received ctrl. type: %d, len: %d", __FUNCTION__, nType, -++ RTMP_Log(RTMP_LOGDEBUG, "%s, received ctrl, type: %d, len: %d", __FUNCTION__, nType, -+ packet->m_nBodySize); -+ /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */ -+ -+@@ -3475,15 +4155,15 @@ HandleCtrl(RTMP *r, const RTMPPacket *packet) -+ RTMP_Log(RTMP_LOGDEBUG, "%s, SWFVerification ping received: ", __FUNCTION__); -+ if (packet->m_nBodySize > 2 && packet->m_body[2] > 0x01) -+ { -+- RTMP_Log(RTMP_LOGERROR, -+- "%s: SWFVerification Type %d request not supported! Patches welcome...", -+- __FUNCTION__, packet->m_body[2]); -++ RTMP_Log(RTMP_LOGERROR, -++ "%s: SWFVerification Type %d request not supported, attempting to use SWFVerification Type 1! Patches welcome...", -++ __FUNCTION__, packet->m_body[2]); -+ } -+ #ifdef CRYPTO -+ /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */ -+ -+ /* respond with HMAC SHA256 of decompressed SWF, key is the 30byte player key, also the last 30 bytes of the server handshake are applied */ -+- else if (r->Link.SWFSize) -++ if (r->Link.SWFSize) -+ { -+ RTMP_SendCtrl(r, 0x1B, 0, 0); -+ } -+@@ -3788,8 +4468,18 @@ HandShake(RTMP *r, int FP9HandShake) -+ serversig[4], serversig[5], serversig[6], serversig[7]); -+ -+ /* 2nd part of handshake */ -+- if (!WriteN(r, serversig, RTMP_SIG_SIZE)) -+- return FALSE; -++ if (r->Link.CombineConnectPacket) -++ { -++ char *HandshakeResponse = malloc(RTMP_SIG_SIZE); -++ memcpy(HandshakeResponse, (char *) serversig, RTMP_SIG_SIZE); -++ r->Link.HandshakeResponse.av_val = HandshakeResponse; -++ r->Link.HandshakeResponse.av_len = RTMP_SIG_SIZE; -++ } -++ else -++ { -++ if (!WriteN(r, (char *) serversig, RTMP_SIG_SIZE)) -++ return FALSE; -++ } -+ -+ if (ReadN(r, serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE) -+ return FALSE; -+@@ -3942,7 +4632,7 @@ RTMP_SendPacket(RTMP *r, RTMPPacket *packet, int queue) -+ -+ nSize = packetSize[packet->m_headerType]; -+ hSize = nSize; cSize = 0; -+- t = packet->m_nTimeStamp - last; -++ t = packet->m_nTimeStamp ? packet->m_nTimeStamp - last : 0; -+ -+ if (packet->m_body) -+ { -+@@ -4251,8 +4941,13 @@ RTMPSockBuf_Fill(RTMPSockBuf *sb) -+ { -+ int nBytes; -+ -+- if (!sb->sb_size) -+- sb->sb_start = sb->sb_buf; -++ /* Copy unprocessed bytes to the start of buffer to make optimum use of -++ * available buffer */ -++ if (sb->sb_start != sb->sb_buf) -++ { -++ memcpy(sb->sb_buf, sb->sb_start, sb->sb_size); -++ sb->sb_start = sb->sb_buf; -++ } -+ -+ while (1) -+ { -+@@ -4266,8 +4961,10 @@ RTMPSockBuf_Fill(RTMPSockBuf *sb) -+ #endif -+ { -+ nBytes = recv(sb->sb_socket, sb->sb_start + sb->sb_size, nBytes, 0); -+- } -+- if (nBytes != -1) -++ if (!nBytes) -++ RTMP_Log(RTMP_LOGDEBUG, "Socket closed by server, nBytes: %d", nBytes); -++ } -++ if (nBytes >= 0) -+ { -+ sb->sb_size += nBytes; -+ } -+@@ -4405,21 +5102,19 @@ static int -+ HTTP_Post(RTMP *r, RTMPTCmd cmd, const char *buf, int len) -+ { -+ char hbuf[512]; -+- int hlen = snprintf(hbuf, sizeof(hbuf), "POST /%s%s/%d HTTP/1.1\r\n" -+- "Host: %.*s:%d\r\n" -+- "Accept: */*\r\n" -+- "User-Agent: Shockwave Flash\r\n" -+- "Connection: Keep-Alive\r\n" -+- "Cache-Control: no-cache\r\n" -+- "Content-type: application/x-fcs\r\n" -+- "Content-length: %d\r\n\r\n", RTMPT_cmds[cmd], -+- r->m_clientID.av_val ? r->m_clientID.av_val : "", -+- r->m_msgCounter, r->Link.hostname.av_len, r->Link.hostname.av_val, -+- r->Link.port, len); -++ int hlen = snprintf(hbuf, sizeof (hbuf), "POST /%s%s/%d HTTP/1.1\r\n" -++ "Content-Type: application/x-fcs\r\n" -++ "User-Agent: Shockwave Flash\r\n" -++ "Host: %.*s:%d\r\n" -++ "Content-Length: %d\r\n" -++ "Connection: Keep-Alive\r\n" -++ "Cache-Control: no-cache\r\n\r\n", RTMPT_cmds[cmd], -++ r->m_clientID.av_val ? r->m_clientID.av_val : "", -++ r->m_msgCounter, r->Link.hostname.av_len, r->Link.hostname.av_val, -++ r->Link.port, len); -+ RTMPSockBuf_Send(&r->m_sb, hbuf, hlen); -+ hlen = RTMPSockBuf_Send(&r->m_sb, buf, len); -+ r->m_msgCounter++; -+- r->m_unackd++; -+ return hlen; -+ } -+ -+@@ -4429,22 +5124,17 @@ HTTP_read(RTMP *r, int fill) -+ char *ptr; -+ int hlen; -+ -+-restart: -+ if (fill) -+ RTMPSockBuf_Fill(&r->m_sb); -+- if (r->m_sb.sb_size < 13) { -+- if (fill) -+- goto restart; -++ -++ /* Check if socket buffer is empty or HTTP header isn't completely received */ -++ memset(r->m_sb.sb_start + r->m_sb.sb_size, '\0', 1); -++ if ((!r->m_sb.sb_size) || (!strstr(r->m_sb.sb_start, "\r\n\r\n"))) -+ return -2; -+- } -++ -+ if (strncmp(r->m_sb.sb_start, "HTTP/1.1 200 ", 13)) -+ return -1; -+ r->m_sb.sb_start[r->m_sb.sb_size] = '\0'; -+- if (!strstr(r->m_sb.sb_start, "\r\n\r\n")) { -+- if (fill) -+- goto restart; -+- return -2; -+- } -+ -+ ptr = r->m_sb.sb_start + sizeof("HTTP/1.1 200"); -+ while ((ptr = strstr(ptr, "Content-"))) { -+@@ -4452,21 +5142,31 @@ restart: -+ ptr += 8; -+ } -+ if (!ptr) -+- return -1; -+- hlen = atoi(ptr+16); -++ { -++ ptr = r->m_sb.sb_start + sizeof ("HTTP/1.1 200"); -++ RTMP_Log(RTMP_LOGDEBUG, "No Content-Length header found, assuming continuous stream"); -++ hlen = 2147483648UL; // 2 GB -++ } -++ else -++ hlen = atoi(ptr + 16); -+ ptr = strstr(ptr+16, "\r\n\r\n"); -+ if (!ptr) -+ return -1; -+ ptr += 4; -+- if (ptr + (r->m_clientID.av_val ? 1 : hlen) > r->m_sb.sb_start + r->m_sb.sb_size) -+- { -+- if (fill) -+- goto restart; -+- return -2; -+- } -+ r->m_sb.sb_size -= ptr - r->m_sb.sb_start; -+ r->m_sb.sb_start = ptr; -+- r->m_unackd--; -++ -++ /* Stop processing if content length is 0 */ -++ if (!hlen) -++ return -3; -++ -++ /* Refill buffer if no payload is received */ -++ if (hlen && (!r->m_sb.sb_size)) -++ { -++ RTMPSockBuf_Fill(&r->m_sb); -++ ptr = r->m_sb.sb_buf; -++ r->m_sb.sb_start = ptr; -++ } -+ -+ if (!r->m_clientID.av_val) -+ { -+@@ -4486,10 +5186,17 @@ restart: -+ r->m_sb.sb_start++; -+ r->m_sb.sb_size--; -+ } -++ -++ /* Following values shouldn't be negative in any case */ -++ if (r->m_resplen < 0) -++ r->m_resplen = 0; -++ if (r->m_sb.sb_size < 0) -++ r->m_sb.sb_size = 0; -++ -+ return 0; -+ } -+ -+-#define MAX_IGNORED_FRAMES 50 -++#define MAX_IGNORED_FRAMES 100 -+ -+ /* Read from the stream until we get a media packet. -+ * Returns -3 if Play.Close/Stop, -2 if fatal error, -1 if no more media -+@@ -4557,162 +5264,156 @@ Read_1_Packet(RTMP *r, char *buf, unsigned int buflen) -+ #endif -+ -+ if (r->m_read.flags & RTMP_READ_RESUME) -+- { -+- /* check the header if we get one */ -+- if (packet.m_nTimeStamp == 0) -+- { -+- if (r->m_read.nMetaHeaderSize > 0 -+- && packet.m_packetType == RTMP_PACKET_TYPE_INFO) -+- { -+- AMFObject metaObj; -+- int nRes = -+- AMF_Decode(&metaObj, packetBody, nPacketLen, FALSE); -+- if (nRes >= 0) -+- { -+- AVal metastring; -+- AMFProp_GetString(AMF_GetProp(&metaObj, NULL, 0), -+- &metastring); -+- -+- if (AVMATCH(&metastring, &av_onMetaData)) -+- { -+- /* compare */ -+- if ((r->m_read.nMetaHeaderSize != nPacketLen) || -+- (memcmp -+- (r->m_read.metaHeader, packetBody, -+- r->m_read.nMetaHeaderSize) != 0)) -+- { -+- ret = RTMP_READ_ERROR; -+- } -+- } -+- AMF_Reset(&metaObj); -+- if (ret == RTMP_READ_ERROR) -+- break; -+- } -+- } -++ { -++ RTMP_Log(RTMP_LOGDEBUG2, "Received timestamp: %d, type %d", -++ packet.m_nTimeStamp, packet.m_packetType); -++ if (packet.m_nTimeStamp > 0 && r->m_read.nResumeDriftTS > 0) -++ packet.m_nTimeStamp -= r->m_read.nResumeDriftTS; -++ RTMP_Log(RTMP_LOGDEBUG2, "Adjusted timestamp: %d", packet.m_nTimeStamp); -++ -++ /* check the header if we get one */ -++ if (r->m_read.nMetaHeaderSize > 0 -++ && packet.m_packetType == RTMP_PACKET_TYPE_INFO) -++ { -++ AMFObject metaObj; -++ int nRes = AMF_Decode(&metaObj, packetBody, nPacketLen, FALSE); -++ if (nRes >= 0) -++ { -++ AVal metastring; -++ AMFProp_GetString(AMF_GetProp(&metaObj, NULL, 0), &metastring); -++ -++ if (AVMATCH(&metastring, &av_onMetaData)) -++ { -++ /* compare */ -++ if ((r->m_read.nMetaHeaderSize != nPacketLen) || -++ (memcmp(r->m_read.metaHeader, packetBody, r->m_read.nMetaHeaderSize) != 0)) -++ { -++ ret = RTMP_READ_ERROR; -++ } -++ } -++ AMF_Reset(&metaObj); -++ if (ret == RTMP_READ_ERROR) -++ break; -++ } -++ } -+ -+- /* check first keyframe to make sure we got the right position -+- * in the stream! (the first non ignored frame) -+- */ -+- if (r->m_read.nInitialFrameSize > 0) -+- { -+- /* video or audio data */ -+- if (packet.m_packetType == r->m_read.initialFrameType -+- && r->m_read.nInitialFrameSize == nPacketLen) -+- { -+- /* we don't compare the sizes since the packet can -+- * contain several FLV packets, just make sure the -+- * first frame is our keyframe (which we are going -+- * to rewrite) -+- */ -+- if (memcmp -+- (r->m_read.initialFrame, packetBody, -+- r->m_read.nInitialFrameSize) == 0) -+- { -+- RTMP_Log(RTMP_LOGDEBUG, "Checked keyframe successfully!"); -+- r->m_read.flags |= RTMP_READ_GOTKF; -+- /* ignore it! (what about audio data after it? it is -+- * handled by ignoring all 0ms frames, see below) -+- */ -+- ret = RTMP_READ_IGNORE; -+- break; -+- } -+- } -++ /* check first keyframe to make sure we got the right position -++ * in the stream! (the first non ignored frame) -++ */ -++ RTMP_Log(RTMP_LOGDEBUG2, "Required packet length: %d, Packet length: %d", -++ r->m_read.nInitialFrameSize, nPacketLen); -++ if (r->m_read.nInitialFrameSize > 0) -++ { -++ /* video or audio data */ -++ if (packet.m_packetType == r->m_read.initialFrameType -++ && r->m_read.nInitialFrameSize == nPacketLen) -++ { -++ /* we don't compare the sizes since the packet can -++ * contain several FLV packets, just make sure the -++ * first frame is our keyframe (which we are going -++ * to rewrite) -++ */ -++ RTMP_Log(RTMP_LOGDEBUG2, "Comparing keyframe data"); -++ if (memcmp(r->m_read.initialFrame, packetBody, -++ r->m_read.nInitialFrameSize) == 0) -++ { -++ RTMP_Log(RTMP_LOGDEBUG, "Checked keyframe successfully!"); -++ r->m_read.flags |= RTMP_READ_GOTKF; -++ r->m_read.nResumeDriftTS = packet.m_nTimeStamp; -++ /* ignore it! (what about audio data after it? it is -++ * handled by ignoring all 0ms frames, see below) -++ */ -++ ret = RTMP_READ_IGNORE; -++ break; -++ } -++ } -+ -+- /* hande FLV streams, even though the server resends the -+- * keyframe as an extra video packet it is also included -+- * in the first FLV stream chunk and we have to compare -+- * it and filter it out !! -+- */ -+- if (packet.m_packetType == RTMP_PACKET_TYPE_FLASH_VIDEO) -+- { -+- /* basically we have to find the keyframe with the -+- * correct TS being nResumeTS -+- */ -+- unsigned int pos = 0; -+- uint32_t ts = 0; -+- -+- while (pos + 11 < nPacketLen) -+- { -+- /* size without header (11) and prevTagSize (4) */ -+- uint32_t dataSize = -+- AMF_DecodeInt24(packetBody + pos + 1); -+- ts = AMF_DecodeInt24(packetBody + pos + 4); -+- ts |= (packetBody[pos + 7] << 24); -++ /* hande FLV streams, even though the server resends the -++ * keyframe as an extra video packet it is also included -++ * in the first FLV stream chunk and we have to compare -++ * it and filter it out !! -++ */ -++ if (packet.m_packetType == RTMP_PACKET_TYPE_FLASH_VIDEO) -++ { -++ /* basically we have to find the keyframe with the -++ * correct TS being nResumeTS -++ */ -++ unsigned int pos = 0; -++ uint32_t ts = 0; -++ -++ while (pos + 11 < nPacketLen) -++ { -++ /* size without header (11) and prevTagSize (4) */ -++ uint32_t dataSize = AMF_DecodeInt24(packetBody + pos + 1); -++ ts = AMF_DecodeInt24(packetBody + pos + 4); -++ ts |= (packetBody[pos + 7] << 24); -+ -+ #ifdef _DEBUG -+- RTMP_Log(RTMP_LOGDEBUG, -+- "keyframe search: FLV Packet: type %02X, dataSize: %d, timeStamp: %d ms", -+- packetBody[pos], dataSize, ts); -++ RTMP_Log(RTMP_LOGDEBUG, -++ "keyframe search: FLV Packet: type %02X, dataSize: %d, timeStamp: %d ms", -++ packetBody[pos], dataSize, ts); -+ #endif -+- /* ok, is it a keyframe?: -+- * well doesn't work for audio! -+- */ -+- if (packetBody[pos /*6928, test 0 */ ] == -+- r->m_read.initialFrameType -+- /* && (packetBody[11]&0xf0) == 0x10 */ ) -+- { -+- if (ts == r->m_read.nResumeTS) -+- { -+- RTMP_Log(RTMP_LOGDEBUG, -+- "Found keyframe with resume-keyframe timestamp!"); -+- if (r->m_read.nInitialFrameSize != dataSize -+- || memcmp(r->m_read.initialFrame, -+- packetBody + pos + 11, -+- r->m_read. -+- nInitialFrameSize) != 0) -+- { -+- RTMP_Log(RTMP_LOGERROR, -+- "FLV Stream: Keyframe doesn't match!"); -+- ret = RTMP_READ_ERROR; -+- break; -+- } -+- r->m_read.flags |= RTMP_READ_GOTFLVK; -+- -+- /* skip this packet? -+- * check whether skippable: -+- */ -+- if (pos + 11 + dataSize + 4 > nPacketLen) -+- { -+- RTMP_Log(RTMP_LOGWARNING, -+- "Non skipable packet since it doesn't end with chunk, stream corrupt!"); -+- ret = RTMP_READ_ERROR; -+- break; -+- } -+- packetBody += (pos + 11 + dataSize + 4); -+- nPacketLen -= (pos + 11 + dataSize + 4); -+- -+- goto stopKeyframeSearch; -+- -+- } -+- else if (r->m_read.nResumeTS < ts) -+- { -+- /* the timestamp ts will only increase with -+- * further packets, wait for seek -+- */ -+- goto stopKeyframeSearch; -+- } -+- } -+- pos += (11 + dataSize + 4); -+- } -+- if (ts < r->m_read.nResumeTS) -+- { -+- RTMP_Log(RTMP_LOGERROR, -+- "First packet does not contain keyframe, all " -+- "timestamps are smaller than the keyframe " -+- "timestamp; probably the resume seek failed?"); -+- } -+- stopKeyframeSearch: -+- ; -+- if (!(r->m_read.flags & RTMP_READ_GOTFLVK)) -+- { -+- RTMP_Log(RTMP_LOGERROR, -+- "Couldn't find the seeked keyframe in this chunk!"); -+- ret = RTMP_READ_IGNORE; -+- break; -+- } -+- } -+- } -+- } -++ /* ok, is it a keyframe?: -++ * well doesn't work for audio! -++ */ -++ if (packetBody[pos /*6928, test 0 */ ] == r->m_read.initialFrameType -++ /* && (packetBody[11]&0xf0) == 0x10 */) -++ { -++ if (ts == r->m_read.nResumeTS) -++ { -++ RTMP_Log(RTMP_LOGDEBUG, "Found keyframe with resume-keyframe timestamp!"); -++ if (r->m_read.nInitialFrameSize != dataSize || -++ memcmp(r->m_read.initialFrame, packetBody + pos + 11, -++ r->m_read.nInitialFrameSize) != 0) -++ { -++ RTMP_Log(RTMP_LOGERROR, "FLV Stream: Keyframe doesn't match!"); -++ ret = RTMP_READ_ERROR; -++ break; -++ } -++ r->m_read.flags |= RTMP_READ_GOTFLVK; -++ -++ /* skip this packet? -++ * check whether skippable: -++ */ -++ if (pos + 11 + dataSize + 4 > nPacketLen) -++ { -++ RTMP_Log(RTMP_LOGWARNING, "Non skipable packet since it doesn't " -++ "end with chunk, stream corrupt!"); -++ ret = RTMP_READ_ERROR; -++ break; -++ } -++ packetBody += (pos + 11 + dataSize + 4); -++ nPacketLen -= (pos + 11 + dataSize + 4); -++ -++ goto stopKeyframeSearch; -++ -++ } -++ else if (r->m_read.nResumeTS < ts) -++ { -++ /* the timestamp ts will only increase with -++ * further packets, wait for seek -++ */ -++ goto stopKeyframeSearch; -++ } -++ } -++ pos += (11 + dataSize + 4); -++ } -++ if (ts < r->m_read.nResumeTS) -++ { -++ RTMP_Log(RTMP_LOGERROR, -++ "First packet does not contain keyframe, all " -++ "timestamps are smaller than the keyframe " -++ "timestamp; probably the resume seek failed?"); -++ } -++ stopKeyframeSearch: -++ if (!(r->m_read.flags & RTMP_READ_GOTFLVK)) -++ { -++ RTMP_Log(RTMP_LOGERROR, "Couldn't find the seeked keyframe in this chunk!"); -++ ret = RTMP_READ_IGNORE; -++ break; -++ } -++ } -++ } -+ -+ if (packet.m_nTimeStamp > 0 -+ && (r->m_read.flags & (RTMP_READ_GOTKF|RTMP_READ_GOTFLVK))) -+@@ -4972,7 +5673,7 @@ static const char flvHeader[] = { 'F', 'L', 'V', 0x01, -+ 0x00, 0x00, 0x00, 0x00 -+ }; -+ -+-#define HEADERBUF (128*1024) -++#define HEADERBUF (1024*1024) -+ int -+ RTMP_Read(RTMP *r, char *buf, int size) -+ { -+@@ -5175,3 +5876,395 @@ RTMP_Write(RTMP *r, const char *buf, int size) -+ } -+ return size+s2; -+ } -++ -++AVal -++AVcopy(AVal src) -++{ -++ AVal dst; -++ if (src.av_len) -++ { -++ dst.av_val = malloc(src.av_len + 1); -++ memcpy(dst.av_val, src.av_val, src.av_len); -++ dst.av_val[src.av_len] = '\0'; -++ dst.av_len = src.av_len; -++ } -++ else -++ { -++ dst.av_val = NULL; -++ dst.av_len = 0; -++ } -++ return dst; -++} -++ -++static int -++ConnectSocket(RTMP *r) -++{ -++ int on = 1; -++ struct sockaddr_in service; -++ if (!r->Link.hostname.av_len) -++ return FALSE; -++ -++ memset(&service, 0, sizeof (struct sockaddr_in)); -++ service.sin_family = AF_INET; -++ -++ if (r->Link.socksport) -++ { -++ /* Connect via SOCKS */ -++ if (!add_addr_info(&service, &r->Link.sockshost, r->Link.socksport)) -++ return FALSE; -++ } -++ else -++ { -++ /* Connect directly */ -++ if (!add_addr_info(&service, &r->Link.hostname, r->Link.port)) -++ return FALSE; -++ } -++ -++ r->m_sb.sb_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); -++ if (r->m_sb.sb_socket != -1) -++ { -++ if (connect(r->m_sb.sb_socket, (struct sockaddr *) &service, sizeof (struct sockaddr)) < 0) -++ { -++ int err = GetSockError(); -++ RTMP_Log(RTMP_LOGERROR, "%s, failed to connect socket. %d (%s)", -++ __FUNCTION__, err, strerror(err)); -++ RTMP_Close(r); -++ return FALSE; -++ } -++ -++ if (r->Link.socksport) -++ { -++ RTMP_Log(RTMP_LOGDEBUG, "%s ... SOCKS negotiation", __FUNCTION__); -++ if (!SocksNegotiate(r)) -++ { -++ RTMP_Log(RTMP_LOGERROR, "%s, SOCKS negotiation failed.", __FUNCTION__); -++ RTMP_Close(r); -++ return FALSE; -++ } -++ } -++ } -++ else -++ { -++ RTMP_Log(RTMP_LOGERROR, "%s, failed to create socket. Error: %d", -++ __FUNCTION__, GetSockError()); -++ return FALSE; -++ } -++ -++ /* set timeout */ -++ SET_RCVTIMEO(tv, r->Link.timeout); -++ if (setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, sizeof (tv))) -++ { -++ RTMP_Log(RTMP_LOGERROR, "%s, Setting socket timeout to %d failed!", -++ __FUNCTION__, r->Link.timeout); -++ } -++ -++ setsockopt(r->m_sb.sb_socket, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof (on)); -++ if (r->Link.protocol & RTMP_FEATURE_HTTP) -++ setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof (on)); -++ -++ return TRUE; -++} -++ -++static int -++SendCommand(RTMP *r, char *method, int queue) -++{ -++ char pbuf[256], *pend = pbuf + sizeof (pbuf), *enc; -++ AVal av_command, methodName; -++ -++ enc = pbuf; -++ methodName.av_val = method; -++ methodName.av_len = strlen(method); -++ enc = AMF_EncodeString(enc, pend, &methodName); -++ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -++ *enc++ = AMF_NULL; -++ av_command.av_val = pbuf; -++ av_command.av_len = enc - pbuf; -++ -++ return SendInvoke(r, &av_command, queue); -++} -++ -++static int -++SendGetStreamLength(RTMP *r) -++{ -++ char pbuf[256], *pend = pbuf + sizeof (pbuf), *enc; -++ AVal av_Command; -++ SAVC(getStreamLength); -++ -++ enc = pbuf; -++ enc = AMF_EncodeString(enc, pend, &av_getStreamLength); -++ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -++ *enc++ = AMF_NULL; -++ enc = AMF_EncodeString(enc, pend, &r->Link.playpath); -++ av_Command.av_val = pbuf; -++ av_Command.av_len = enc - pbuf; -++ -++ return SendInvoke(r, &av_Command, TRUE); -++} -++ -++static int -++SendInvoke(RTMP *r, AVal *command, int queue) -++{ -++ RTMPPacket packet; -++ char pbuf[512], *enc; -++ -++ packet.m_nChannel = 0x03; /* control channel (invoke) */ -++ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM; -++ packet.m_packetType = RTMP_PACKET_TYPE_INVOKE; -++ packet.m_nTimeStamp = 0; -++ packet.m_nInfoField2 = 0; -++ packet.m_hasAbsTimestamp = 0; -++ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE; -++ -++ enc = packet.m_body; -++ if (command->av_len) -++ { -++ memcpy(enc, command->av_val, command->av_len); -++ enc += command->av_len; -++ } -++ else -++ return FALSE; -++ packet.m_nBodySize = enc - packet.m_body; -++ -++ return RTMP_SendPacket(r, &packet, queue); -++} -++ -++AVal -++StripParams(AVal *src) -++{ -++ AVal str; -++ if (src->av_val) -++ { -++ str.av_val = calloc(src->av_len + 1, sizeof (char)); -++ strncpy(str.av_val, src->av_val, src->av_len); -++ str.av_len = src->av_len; -++ char *start = str.av_val; -++ char *end = start + str.av_len; -++ char *ptr = start; -++ -++ while (ptr < end) -++ { -++ if (*ptr == '?') -++ { -++ str.av_len = ptr - start; -++ break; -++ } -++ ptr++; -++ } -++ memset(start + str.av_len, 0, 1); -++ -++ char *dynamic = strstr(start, "[[DYNAMIC]]"); -++ if (dynamic) -++ { -++ dynamic -= 1; -++ memset(dynamic, 0, 1); -++ str.av_len = dynamic - start; -++ end = start + str.av_len; -++ } -++ -++ char *import = strstr(start, "[[IMPORT]]"); -++ if (import) -++ { -++ str.av_val = import + 11; -++ strcpy(start, "http://"); -++ str.av_val = strcat(start, str.av_val); -++ str.av_len = strlen(str.av_val); -++ } -++ return str; -++ } -++ str = *src; -++ return str; -++} -++ -++char * -++strreplace(char *srcstr, int srclen, char *orig, char *repl, int didAlloc) -++{ -++ char *ptr = NULL, *sptr = srcstr; -++ int origlen = strlen(orig); -++ int repllen = strlen(repl); -++ if (!srclen) -++ srclen = strlen(srcstr); -++ char *srcend = srcstr + srclen; -++ int dstbuffer = srclen / origlen * repllen; -++ if (dstbuffer < srclen) -++ dstbuffer = srclen; -++ char *dststr = calloc(dstbuffer + 1, sizeof (char)); -++ char *dptr = dststr; -++ -++ if ((ptr = strstr(srcstr, orig))) -++ { -++ while (ptr < srcend && (ptr = strstr(sptr, orig))) -++ { -++ int len = ptr - sptr; -++ memcpy(dptr, sptr, len); -++ sptr += len + origlen; -++ dptr += len; -++ memcpy(dptr, repl, repllen); -++ dptr += repllen; -++ } -++ memcpy(dptr, sptr, srcend - sptr); -++ if (didAlloc) -++ free(srcstr); -++ return dststr; -++ } -++ -++ memcpy(dststr, srcstr, srclen); -++ if (didAlloc) -++ free(srcstr); -++ return dststr; -++} -++ -++int -++strsplit(char *src, int srclen, char delim, char ***params) -++{ -++ char *sptr, *srcbeg, *srcend, *dstr; -++ int count = 1, i = 0, len = 0; -++ -++ if (src == NULL) -++ return 0; -++ if (!srclen) -++ srclen = strlen(src); -++ srcbeg = src; -++ srcend = srcbeg + srclen; -++ sptr = srcbeg; -++ -++ /* count the delimiters */ -++ while (sptr < srcend) -++ { -++ if (*sptr++ == delim) -++ count++; -++ } -++ sptr = srcbeg; -++ *params = malloc(count * sizeof (size_t)); -++ char **param = *params; -++ -++ for (i = 0; i < (count - 1); i++) -++ { -++ dstr = strchr(sptr, delim); -++ len = dstr - sptr; -++ param[i] = malloc((len + 1) * sizeof (char)); -++ memcpy(param[i], sptr, len); -++ *(param[i] + len) = '\0'; -++ sptr += len + 1; -++ } -++ -++ /* copy the last string */ -++ if (sptr <= srcend) -++ { -++ len = srclen - (sptr - srcbeg); -++ param[i] = malloc((len + 1) * sizeof (char)); -++ memcpy(param[i], sptr, len); -++ *(param[i] + len) = '\0'; -++ } -++ return count; -++} -++ -++void -++TransformRot13(AMFObject *obj, AVal *rindex, AVal *r) -++{ -++ char *chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMabcdefghijklmnopqrstuvwxyzabcdefghijklm"; -++ int i = 0, pos = 0; -++ AMFObject obj2; -++ -++ AMFProp_GetObject(AMF_GetProp(obj, NULL, 3), &obj2); -++ AMFProp_GetString(AMF_GetProp(&obj2, rindex, -1), r); -++ -++ for (i = 0; i < r->av_len; i++) -++ { -++ char *chr = &r->av_val[i]; -++ chr = strchr(chars, *chr); -++ pos = chr ? chr - chars : -1; -++ if (pos > -1) -++ r->av_val[i] = chars[pos + 13]; -++ } -++} -++ -++void -++__TeaCrypt(uint32_t *block, uint32_t len, uint32_t *key) -++{ -++ uint32_t z = block[len - 1], y = block[0], sum = 0, e, DELTA = 0x9e3779b9; -++ int32_t p, q; -++ -++ q = 6 + 52 / len; -++ while (q-- > 0) -++ { -++ sum += DELTA; -++ e = (sum >> 2) & 3; -++ for (p = 0; p < len - 1; p++) -++ { -++ y = block[p + 1]; -++ block[p] += ((z >> 5^y << 2) + (y >> 3^z << 4)) ^ ((sum^y) + (key[(p & 3)^e] ^ z)); -++ z = block[p]; -++ } -++ y = block[0]; -++ block[len - 1] += ((z >> 5^y << 2) + (y >> 3^z << 4)) ^ ((sum^y) + (key[(p & 3)^e] ^ z)); -++ z = block[len - 1]; -++ } -++} -++ -++AVal -++TeaEncrypt(AVal *srcData, AVal *srcKey) -++{ -++ int i, reqPadding, longKeyBlocks, longDataBlocks; -++ unsigned char *key, *data; -++ -++ // Prepare key -++ int srcKeyLen = srcKey->av_len; -++ int reqKeyLen = 16; -++ reqPadding = reqKeyLen - srcKeyLen; -++ if (reqPadding < 0) -++ { -++ reqPadding = 0; -++ srcKeyLen = reqKeyLen; -++ } -++ key = calloc((srcKeyLen + reqPadding + 1), sizeof (char)); -++ memcpy(key, srcKey->av_val, srcKeyLen); -++ longKeyBlocks = reqKeyLen / 4; -++ uint32_t *longKeyBuf = (uint32_t *) malloc(longKeyBlocks * sizeof (uint32_t)); -++ for (i = 0; i < longKeyBlocks; i++) -++ { -++ longKeyBuf[i] = 0; -++ longKeyBuf[i] |= (key[i * 4 + 0]) | (key[i * 4 + 1] << 8) | (key[i * 4 + 2] << 16) | (key[i * 4 + 3] << 24); -++ } -++ -++ // Prepare data -++ int srcDataLen = srcData->av_len; -++ reqPadding = ((int) ((srcDataLen + 3) / 4))*4 - srcDataLen; -++ if ((srcDataLen + reqPadding) < 8) -++ reqPadding = 8 - srcDataLen; -++ data = calloc((srcDataLen + reqPadding + 1), sizeof (char)); -++ memcpy(data, srcData->av_val, srcDataLen); -++ longDataBlocks = (srcDataLen + reqPadding) / 4; -++ uint32_t *longDataBuf = malloc(longDataBlocks * sizeof (uint32_t)); -++ for (i = 0; i < longDataBlocks; i++) -++ { -++ longDataBuf[i] = 0; -++ longDataBuf[i] |= (data[i * 4 + 0]) | (data[i * 4 + 1] << 8) | (data[i * 4 + 2] << 16) | (data[i * 4 + 3] << 24); -++ } -++ -++ // Encrypt data -++ __TeaCrypt(longDataBuf, longDataBlocks, longKeyBuf); -++ -++ // Convert data back to char array -++ for (i = 0; i < longDataBlocks; i++) -++ { -++ data[i * 4 + 0] = longDataBuf[i] & 0xFF; -++ data[i * 4 + 1] = (longDataBuf[i] >> 8) & 0xFF; -++ data[i * 4 + 2] = (longDataBuf[i] >> 16) & 0xFF; -++ data[i * 4 + 3] = (longDataBuf[i] >> 24) & 0xFF; -++ } -++ -++ // Convert to hex string -++ AVal hexData; -++ hexData.av_val = calloc((longDataBlocks * 4 * 2) + 1, sizeof (char)); -++ for (i = 0; i < (longDataBlocks * 4); i++) -++ sprintf(&hexData.av_val[i * 2], "%.2X", data[i]); -++ hexData.av_len = strlen(hexData.av_val); -++ -++ // Free allocated resources -++ free(key); -++ free(longKeyBuf); -++ free(data); -++ free(longDataBuf); -++ -++ return hexData; -++} -+diff --git librtmp/rtmp.h librtmp/rtmp.h -+index 0248913..3e573da 100644 -+--- librtmp/rtmp.h -++++ librtmp/rtmp.h -+@@ -150,12 +150,15 @@ extern "C" -+ AVal playpath; /* passed in explicitly */ -+ AVal tcUrl; -+ AVal swfUrl; -++ AVal swfHash; -+ AVal pageUrl; -+ AVal app; -+ AVal auth; -+ AVal flashVer; -+ AVal subscribepath; -++ AVal ccomm; -+ AVal usherToken; -++ AVal WeebToken; -+ AVal token; -+ AVal pubUser; -+ AVal pubPasswd; -+@@ -175,9 +178,18 @@ extern "C" -+ int lFlags; -+ -+ int swfAge; -++ int swfSize; -+ -+ int protocol; -++ int ConnectPacket; -++ int CombineConnectPacket; -++ int redirected; -+ int timeout; /* connection timeout in seconds */ -++ int dynamicPublish; -++ AVal dynamicCommand; -++ AVal Extras; -++ AVal HandshakeResponse; -++ double publishId; -+ -+ int pFlags; /* unused, but kept to avoid breaking ABI */ -+ -+@@ -220,6 +232,7 @@ extern "C" -+ /* if bResume == TRUE */ -+ uint8_t initialFrameType; -+ uint32_t nResumeTS; -++ uint32_t nResumeDriftTS; -+ char *metaHeader; -+ char *initialFrame; -+ uint32_t nMetaHeaderSize; -+@@ -306,6 +319,8 @@ extern "C" -+ AVal *flashVer, -+ AVal *subscribepath, -+ AVal *usherToken, -++ AVal *WeebToken, -++ AVal *ccomm, -+ int dStart, -+ int dStop, int bLiveStream, long int timeout); -+ -+@@ -371,6 +386,11 @@ extern "C" -+ int RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash, -+ int age); -+ -++ AVal AVcopy(AVal src); -++ AVal StripParams(AVal *src); -++ char *strreplace(char *srcstr, int srclen, char *orig, char *repl, int didAlloc); -++ int strsplit(char *src, int srclen, char delim, char ***params); -++ -+ #ifdef __cplusplus -+ }; -+ #endif -+diff --git librtmp/rtmp_sys.h librtmp/rtmp_sys.h -+index 85d7e53..b2a3438 100644 -+--- librtmp/rtmp_sys.h -++++ librtmp/rtmp_sys.h -+@@ -65,6 +65,7 @@ -+ #include <polarssl/net.h> -+ #include <polarssl/ssl.h> -+ #include <polarssl/havege.h> -++#include <polarssl/md5.h> -+ #if POLARSSL_VERSION_NUMBER < 0x01010000 -+ #define havege_random havege_rand -+ #endif -+@@ -105,6 +106,7 @@ typedef struct tls_server_ctx { -+ #define TLS_write(s,b,l) ssl_write(s,(unsigned char *)b,l) -+ #define TLS_shutdown(s) ssl_close_notify(s) -+ #define TLS_close(s) ssl_free(s); free(s) -++#define md5_hash(i, ilen, o) md5(i, ilen, o) -+ -+ #elif defined(USE_GNUTLS) -+ #include <gnutls/gnutls.h> -+@@ -122,6 +124,8 @@ typedef struct tls_ctx { -+ #define TLS_write(s,b,l) gnutls_record_send(s,b,l) -+ #define TLS_shutdown(s) gnutls_bye(s, GNUTLS_SHUT_RDWR) -+ #define TLS_close(s) gnutls_deinit(s) -++#define md5_hash(i, ilen, o) gnutls_digest_algorithm_t algorithm = GNUTLS_DIG_MD5;\ -++ gnutls_hash_fast(algorithm, i, ilen, o); -+ -+ #else /* USE_OPENSSL */ -+ #define TLS_CTX SSL_CTX * -+@@ -134,6 +138,7 @@ typedef struct tls_ctx { -+ #define TLS_write(s,b,l) SSL_write(s,b,l) -+ #define TLS_shutdown(s) SSL_shutdown(s) -+ #define TLS_close(s) SSL_free(s) -++#define md5_hash(i, ilen, o) MD5(i, ilen, o) -+ -+ #endif -+ #endif -+diff --git rtmpdump.c rtmpdump.c -+index 13741a7..b3ae33f 100644 -+--- rtmpdump.c -++++ rtmpdump.c -+@@ -36,6 +36,9 @@ -+ #ifdef WIN32 -+ #define fseeko fseeko64 -+ #define ftello ftello64 -++#ifdef __MINGW32__ -++#define off_t off64_t -++#endif -+ #include <io.h> -+ #include <fcntl.h> -+ #define SET_BINMODE(f) setmode(fileno(f), O_BINARY) -+@@ -67,7 +70,7 @@ InitSockets() -+ #endif -+ } -+ -+-inline void -++static inline void -+ CleanupSockets() -+ { -+ #ifdef WIN32 -+@@ -148,9 +151,9 @@ OpenResumeFile(const char *flvFile, // file name [in] -+ if (!*file) -+ return RD_SUCCESS; // RD_SUCCESS, because we go to fresh file mode instead of quiting -+ -+- fseek(*file, 0, SEEK_END); -++ fseeko(*file, 0, SEEK_END); -+ *size = ftello(*file); -+- fseek(*file, 0, SEEK_SET); -++ fseeko(*file, 0, SEEK_SET); -+ -+ if (*size > 0) -+ { -+@@ -178,7 +181,7 @@ OpenResumeFile(const char *flvFile, // file name [in] -+ } -+ -+ uint32_t dataOffset = AMF_DecodeInt32(hbuf + 5); -+- fseek(*file, dataOffset, SEEK_SET); -++ fseeko(*file, dataOffset, SEEK_SET); -+ -+ if (fread(hbuf, 1, 4, *file) != 4) -+ { -+@@ -283,18 +286,24 @@ GetLastKeyframe(FILE * file, // output file [in] -+ uint8_t dataType; -+ int bAudioOnly; -+ off_t size; -++ char *syncbuf, *p; -+ -+- fseek(file, 0, SEEK_END); -++ fseeko(file, 0, SEEK_END); -+ size = ftello(file); -++ if (size <= 0) -++ { -++ dSeek = 0; -++ return RD_SUCCESS; -++ } -+ -+- fseek(file, 4, SEEK_SET); -++ fseeko(file, 4, SEEK_SET); -+ if (fread(&dataType, sizeof(uint8_t), 1, file) != 1) -+ return RD_FAILED; -+ -+ bAudioOnly = (dataType & 0x4) && !(dataType & 0x1); -+ -+- RTMP_Log(RTMP_LOGDEBUG, "bAudioOnly: %d, size: %llu", bAudioOnly, -+- (unsigned long long) size); -++ RTMP_Log(RTMP_LOGDEBUG, "bAudioOnly: %d, size: %lu", bAudioOnly, -++ (unsigned long) size); -+ -+ // ok, we have to get the timestamp of the last keyframe (only keyframes are seekable) / last audio frame (audio only streams) -+ -+@@ -326,6 +335,51 @@ GetLastKeyframe(FILE * file, // output file [in] -+ prevTagSize = AMF_DecodeInt32(buffer); -+ //RTMP_Log(RTMP_LOGDEBUG, "Last packet: prevTagSize: %d", prevTagSize); -+ -++ if (prevTagSize <= 0 || prevTagSize > size - 4 - 13) -++ { -++ /* Last packet was not fully received - try to sync to last tag */ -++ prevTagSize = 0; -++ tsize = size > 0x100000 ? 0x100000 : size; /* 1MB should be enough for 3500K bitrates */ -++ if (tsize > 13 + 15) -++ { -++ tsize -= 13; // do not read header -++ syncbuf = (char *) malloc(tsize); -++ if (syncbuf) -++ { -++ fseeko(file, size - tsize, SEEK_SET); -++ if (fread(syncbuf, 1, tsize, file) == tsize) -++ { -++ p = syncbuf + tsize; -++ while (p >= syncbuf + 15) -++ { -++ /* Check for StreamID */ -++ if (AMF_DecodeInt24(p - 7) == 0) -++ { -++ /* Check for Audio/Video/Script */ -++ dataType = p[-15] & 0x1F; -++ if (dataType == 8 || dataType == 9 || dataType == 18) -++ { -++ prevTagSize = AMF_DecodeInt24(p - 14); -++ if ((prevTagSize < tsize) && (p + prevTagSize + 11 <= syncbuf + tsize - 4) -++ && (AMF_DecodeInt32(p - 4 + prevTagSize) == prevTagSize + 11)) -++ { -++ prevTagSize = syncbuf + tsize - p + 15; -++ RTMP_Log(RTMP_LOGDEBUG, "Sync success - found last tag at 0x%x", (uint32_t) (size - prevTagSize)); -++ prevTagSize -= 4; -++ tsize = 0; -++ break; -++ } -++ else -++ prevTagSize = 0; -++ } -++ } -++ --p; -++ } -++ } -++ free(syncbuf); -++ } -++ } -++ } -+ if (prevTagSize == 0) -+ { -+ RTMP_Log(RTMP_LOGERROR, "Couldn't find keyframe to resume from!"); -+@@ -703,8 +757,12 @@ void usage(char *prog) -+ RTMP_LogPrintf -+ ("--token|-T key Key for SecureToken response\n"); -+ RTMP_LogPrintf -++ ("--ccommand|-K key Send custom command before play\n"); -++ RTMP_LogPrintf -+ ("--jtv|-j JSON Authentication token for Justin.tv legacy servers\n"); -+ RTMP_LogPrintf -++ ("--weeb|-J string Authentication token for weeb.tv servers\n"); -++ RTMP_LogPrintf -+ ("--hashes|-# Display progress with hashes, not with the byte counter\n"); -+ RTMP_LogPrintf -+ ("--buffer|-b Buffer time in milliseconds (default: %u)\n", -+@@ -751,7 +809,9 @@ main(int argc, char **argv) -+ AVal hostname = { 0, 0 }; -+ AVal playpath = { 0, 0 }; -+ AVal subscribepath = { 0, 0 }; -+- AVal usherToken = { 0, 0 }; //Justin.tv auth token -++ AVal usherToken = { 0, 0 }; // Justin.tv auth token -++ AVal WeebToken = { 0, 0 }; // Weeb.tv auth token -++ AVal ccomm = { 0, 0 }; -+ int port = -1; -+ int protocol = RTMP_PROTOCOL_UNDEFINED; -+ int retries = 0; -+@@ -853,17 +913,19 @@ main(int argc, char **argv) -+ {"start", 1, NULL, 'A'}, -+ {"stop", 1, NULL, 'B'}, -+ {"token", 1, NULL, 'T'}, -++ {"ccommand", 1, NULL, 'K'}, -+ {"hashes", 0, NULL, '#'}, -+ {"debug", 0, NULL, 'z'}, -+ {"quiet", 0, NULL, 'q'}, -+ {"verbose", 0, NULL, 'V'}, -+ {"jtv", 1, NULL, 'j'}, -++ {"weeb", 1, NULL, 'J'}, -+ {0, 0, 0, 0} -+ }; -+ -+ while ((opt = -+ getopt_long(argc, argv, -+- "hVveqzRr:s:t:i:p:a:b:f:o:u:C:n:c:l:y:Ym:k:d:A:B:T:w:x:W:X:S:#j:", -++ "hVveqzRr:s:t:i:p:a:b:f:o:u:C:n:c:l:y:Ym:k:d:A:B:T:K:w:x:W:X:S:#j:J:", -+ longopts, NULL)) != -1) -+ { -+ switch (opt) -+@@ -995,7 +1057,7 @@ main(int argc, char **argv) -+ port = parsedPort; -+ if (playpath.av_len == 0 && parsedPlaypath.av_len) -+ { -+- playpath = parsedPlaypath; -++ playpath = AVcopy(parsedPlaypath); -+ } -+ if (protocol == RTMP_PROTOCOL_UNDEFINED) -+ protocol = parsedProtocol; -+@@ -1061,6 +1123,9 @@ main(int argc, char **argv) -+ RTMP_SetOpt(&rtmp, &av_token, &token); -+ } -+ break; -++ case 'K': -++ STR2AVAL(ccomm, optarg); -++ break; -+ case '#': -+ bHashes = TRUE; -+ break; -+@@ -1079,6 +1144,9 @@ main(int argc, char **argv) -+ case 'j': -+ STR2AVAL(usherToken, optarg); -+ break; -++ case 'J': -++ STR2AVAL(WeebToken, optarg); -++ break; -+ default: -+ RTMP_LogPrintf("unknown option: %c\n", opt); -+ usage(argv[0]); -+@@ -1170,14 +1238,14 @@ main(int argc, char **argv) -+ -+ if (tcUrl.av_len == 0) -+ { -+- tcUrl.av_len = strlen(RTMPProtocolStringsLower[protocol]) + -+- hostname.av_len + app.av_len + sizeof("://:65535/"); -++ tcUrl.av_len = strlen(RTMPProtocolStringsLower[protocol]) + -++ hostname.av_len + app.av_len + sizeof ("://:65535/"); -+ tcUrl.av_val = (char *) malloc(tcUrl.av_len); -+- if (!tcUrl.av_val) -+- return RD_FAILED; -++ if (!tcUrl.av_val) -++ return RD_FAILED; -+ tcUrl.av_len = snprintf(tcUrl.av_val, tcUrl.av_len, "%s://%.*s:%d/%.*s", -+- RTMPProtocolStringsLower[protocol], hostname.av_len, -+- hostname.av_val, port, app.av_len, app.av_val); -++ RTMPProtocolStringsLower[protocol], hostname.av_len, -++ hostname.av_val, port, app.av_len, app.av_val); -+ } -+ -+ int first = 1; -+@@ -1197,8 +1265,9 @@ main(int argc, char **argv) -+ if (!fullUrl.av_len) -+ { -+ RTMP_SetupStream(&rtmp, protocol, &hostname, port, &sockshost, &playpath, -+- &tcUrl, &swfUrl, &pageUrl, &app, &auth, &swfHash, swfSize, -+- &flashVer, &subscribepath, &usherToken, dSeek, dStopOffset, bLiveStream, timeout); -++ &tcUrl, &swfUrl, &pageUrl, &app, &auth, &swfHash, swfSize, -++ &flashVer, &subscribepath, &usherToken, &WeebToken, &ccomm, -++ dSeek, dStopOffset, bLiveStream, timeout); -+ } -+ else -+ { -+diff --git rtmpgw.c rtmpgw.c -+index 3e47602..e56b855 100644 -+--- rtmpgw.c -++++ rtmpgw.c -+@@ -96,7 +96,9 @@ typedef struct -+ AVal flashVer; -+ AVal token; -+ AVal subscribepath; -+- AVal usherToken; //Justin.tv auth token -++ AVal ccomm; -++ AVal usherToken; // Justin.tv auth token -++ AVal WeebToken; // Weeb.tv auth token -+ AVal sockshost; -+ AMFObject extras; -+ int edepth; -+@@ -556,8 +558,8 @@ void processTCPrequest(STREAMING_SERVER * server, // server socket and state (ou -+ if (!req.fullUrl.av_len) -+ { -+ RTMP_SetupStream(&rtmp, req.protocol, &req.hostname, req.rtmpport, &req.sockshost, -+- &req.playpath, &req.tcUrl, &req.swfUrl, &req.pageUrl, &req.app, &req.auth, &req.swfHash, req.swfSize, &req.flashVer, &req.subscribepath, &req.usherToken, dSeek, req.dStopOffset, -+- req.bLiveStream, req.timeout); -++ &req.playpath, &req.tcUrl, &req.swfUrl, &req.pageUrl, &req.app, &req.auth, &req.swfHash, req.swfSize, &req.flashVer, &req.subscribepath, -++ &req.usherToken, &req.WeebToken, &req.ccomm, dSeek, req.dStopOffset, req.bLiveStream, req.timeout); -+ } -+ else -+ { -+@@ -972,6 +974,12 @@ ParseOption(char opt, char *arg, RTMP_REQUEST * req) -+ case 'j': -+ STR2AVAL(req->usherToken, arg); -+ break; -++ case 'J': -++ STR2AVAL(req->WeebToken, arg); -++ break; -++ case 'K': -++ STR2AVAL(req->ccomm, arg); -++ break; -+ default: -+ RTMP_LogPrintf("unknown option: %c, arg: %s\n", opt, arg); -+ return FALSE; -+@@ -1044,6 +1052,8 @@ main(int argc, char **argv) -+ {"quiet", 0, NULL, 'q'}, -+ {"verbose", 0, NULL, 'V'}, -+ {"jtv", 1, NULL, 'j'}, -++ {"weeb", 1, NULL, 'J'}, -++ {"ccommand", 1, NULL, 'K'}, -+ {0, 0, 0, 0} -+ }; -+ -+@@ -1056,7 +1066,7 @@ main(int argc, char **argv) -+ -+ while ((opt = -+ getopt_long(argc, argv, -+- "hvqVzr:s:t:i:p:a:f:u:n:c:l:y:m:d:D:A:B:T:g:w:x:W:X:S:j:", longopts, -++ "hvqVzr:s:t:i:p:a:f:u:n:c:l:y:m:d:D:A:B:T:g:w:x:W:X:S:j:J:", longopts, -+ NULL)) != -1) -+ { -+ switch (opt) -+@@ -1119,8 +1129,12 @@ main(int argc, char **argv) -+ RTMP_LogPrintf -+ ("--token|-T key Key for SecureToken response\n"); -+ RTMP_LogPrintf -++ ("--ccommand|-K key Send custom command before play\n"); -++ RTMP_LogPrintf -+ ("--jtv|-j JSON Authentication token for Justin.tv legacy servers\n"); -+ RTMP_LogPrintf -++ ("--weeb|-J string Authentication token for weeb.tv servers\n"); -++ RTMP_LogPrintf -+ ("--buffer|-b Buffer time in milliseconds (default: %u)\n\n", -+ defaultRTMPRequest.bufferTime); -+ -+diff --git rtmpsrv.c rtmpsrv.c -+index 5df4d3a..eccaa9c 100644 -+--- rtmpsrv.c -++++ rtmpsrv.c -+@@ -25,9 +25,13 @@ -+ */ -+ -+ #include <stdlib.h> -++#ifdef __MINGW_H -++#include <unistd.h> -++#endif -+ #include <string.h> -+ #include <math.h> -+ #include <limits.h> -++#include <time.h> -+ -+ #include <signal.h> -+ #include <getopt.h> -+@@ -94,12 +98,19 @@ typedef struct -+ STREAMING_SERVER *rtmpServer = 0; // server structure pointer -+ void *sslCtx = NULL; -+ -++int file_exists(const char *fname); -+ STREAMING_SERVER *startStreaming(const char *address, int port); -+ void stopStreaming(STREAMING_SERVER * server); -+ void AVreplace(AVal *src, const AVal *orig, const AVal *repl); -+ -+ static const AVal av_dquote = AVC("\""); -+ static const AVal av_escdquote = AVC("\\\""); -++#ifdef WIN32 -++static const AVal av_caret = AVC("^"); -++static const AVal av_esccaret = AVC("^^"); -++static const AVal av_pipe = AVC("|"); -++static const AVal av_escpipe = AVC("^|"); -++#endif -+ -+ typedef struct -+ { -+@@ -168,6 +179,12 @@ SAVC(level); -+ SAVC(code); -+ SAVC(description); -+ SAVC(secureToken); -++SAVC(_checkbw); -++SAVC(_onbwdone); -++SAVC(checkBandwidth); -++SAVC(onBWDone); -++SAVC(FCSubscribe); -++SAVC(onFCSubscribe); -+ -+ static int -+ SendConnectResult(RTMP *r, double txn) -+@@ -191,7 +208,7 @@ SendConnectResult(RTMP *r, double txn) -+ enc = AMF_EncodeNumber(enc, pend, txn); -+ *enc++ = AMF_OBJECT; -+ -+- STR2AVAL(av, "FMS/3,5,1,525"); -++ STR2AVAL(av, "FMS/3,5,7,7009"); -+ enc = AMF_EncodeNamedString(enc, pend, &av_fmsVer, &av); -+ enc = AMF_EncodeNamedNumber(enc, pend, &av_capabilities, 31.0); -+ enc = AMF_EncodeNamedNumber(enc, pend, &av_mode, 1.0); -+@@ -213,7 +230,7 @@ SendConnectResult(RTMP *r, double txn) -+ enc = AMF_EncodeNamedString(enc, pend, &av_secureToken, &av); -+ #endif -+ STR2AVAL(p.p_name, "version"); -+- STR2AVAL(p.p_vu.p_aval, "3,5,1,525"); -++ STR2AVAL(p.p_vu.p_aval, "3,5,7,7009"); -+ p.p_type = AMF_STRING; -+ obj.o_num = 1; -+ obj.o_props = &p; -+@@ -234,7 +251,7 @@ static int -+ SendResultNumber(RTMP *r, double txn, double ID) -+ { -+ RTMPPacket packet; -+- char pbuf[256], *pend = pbuf+sizeof(pbuf); -++ char pbuf[1024], *pend = pbuf + sizeof (pbuf); -+ -+ packet.m_nChannel = 0x03; // control channel (invoke) -+ packet.m_headerType = 1; /* RTMP_PACKET_SIZE_MEDIUM; */ -+@@ -264,12 +281,13 @@ static const AVal av_Stopped_playing = AVC("Stopped playing"); -+ SAVC(details); -+ SAVC(clientid); -+ static const AVal av_NetStream_Authenticate_UsherToken = AVC("NetStream.Authenticate.UsherToken"); -++static const AVal av_FCSubscribe_message = AVC("FCSubscribe to stream"); -+ -+ static int -+ SendPlayStart(RTMP *r) -+ { -+ RTMPPacket packet; -+- char pbuf[512], *pend = pbuf+sizeof(pbuf); -++ char pbuf[1024], *pend = pbuf + sizeof (pbuf); -+ -+ packet.m_nChannel = 0x03; // control channel (invoke) -+ packet.m_headerType = 1; /* RTMP_PACKET_SIZE_MEDIUM; */ -+@@ -301,7 +319,7 @@ static int -+ SendPlayStop(RTMP *r) -+ { -+ RTMPPacket packet; -+- char pbuf[512], *pend = pbuf+sizeof(pbuf); -++ char pbuf[1024], *pend = pbuf + sizeof (pbuf); -+ -+ packet.m_nChannel = 0x03; // control channel (invoke) -+ packet.m_headerType = 1; /* RTMP_PACKET_SIZE_MEDIUM; */ -+@@ -329,6 +347,83 @@ SendPlayStop(RTMP *r) -+ return RTMP_SendPacket(r, &packet, FALSE); -+ } -+ -++static int -++SendCheckBWResponse(RTMP *r, int oldMethodType, int onBWDoneInit) -++{ -++ RTMPPacket packet; -++ char pbuf[1024], *pend = pbuf + sizeof (pbuf); -++ char *enc; -++ -++ packet.m_nChannel = 0x03; /* control channel (invoke) */ -++ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM; -++ packet.m_packetType = RTMP_PACKET_TYPE_INVOKE; -++ packet.m_nTimeStamp = 0; -++ packet.m_nInfoField2 = 0; -++ packet.m_hasAbsTimestamp = 0; -++ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE; -++ -++ enc = packet.m_body; -++ if (oldMethodType) -++ { -++ enc = AMF_EncodeString(enc, pend, &av__onbwdone); -++ enc = AMF_EncodeNumber(enc, pend, 0); -++ *enc++ = AMF_NULL; -++ enc = AMF_EncodeNumber(enc, pend, 10240); -++ enc = AMF_EncodeNumber(enc, pend, 0); -++ } -++ else -++ { -++ enc = AMF_EncodeString(enc, pend, &av_onBWDone); -++ enc = AMF_EncodeNumber(enc, pend, 0); -++ *enc++ = AMF_NULL; -++ if (!onBWDoneInit) -++ { -++ enc = AMF_EncodeNumber(enc, pend, 10240); -++ enc = AMF_EncodeNumber(enc, pend, 0); -++ enc = AMF_EncodeNumber(enc, pend, 0); -++ enc = AMF_EncodeNumber(enc, pend, 20); -++ } -++ } -++ -++ packet.m_nBodySize = enc - packet.m_body; -++ -++ return RTMP_SendPacket(r, &packet, FALSE); -++} -++ -++static int -++SendOnFCSubscribe(RTMP *r) -++{ -++ RTMPPacket packet; -++ char pbuf[1024], *pend = pbuf + sizeof (pbuf); -++ char *enc; -++ -++ packet.m_nChannel = 0x03; /* control channel (invoke) */ -++ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM; -++ packet.m_packetType = RTMP_PACKET_TYPE_INVOKE; -++ packet.m_nTimeStamp = 0; -++ packet.m_nInfoField2 = 0; -++ packet.m_hasAbsTimestamp = 0; -++ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE; -++ -++ enc = packet.m_body; -++ enc = AMF_EncodeString(enc, pend, &av_onFCSubscribe); -++ enc = AMF_EncodeNumber(enc, pend, 0); -++ *enc++ = AMF_NULL; -++ -++ *enc++ = AMF_OBJECT; -++ enc = AMF_EncodeNamedString(enc, pend, &av_level, &av_status); -++ enc = AMF_EncodeNamedString(enc, pend, &av_code, &av_NetStream_Play_Start); -++ enc = AMF_EncodeNamedString(enc, pend, &av_description, &av_FCSubscribe_message); -++ enc = AMF_EncodeNamedNumber(enc, pend, &av_clientid, 0); -++ *enc++ = 0; -++ *enc++ = 0; -++ *enc++ = AMF_OBJECT_END; -++ -++ packet.m_nBodySize = enc - packet.m_body; -++ -++ return RTMP_SendPacket(r, &packet, FALSE); -++} -++ -+ static void -+ spawn_dumper(int argc, AVal *av, char *cmd) -+ { -+@@ -389,6 +484,8 @@ countAMF(AMFObject *obj, int *argc) -+ len += 40; -+ break; -+ case AMF_OBJECT: -++ case AMF_ECMA_ARRAY: -++ case AMF_STRICT_ARRAY: -+ len += 9; -+ len += countAMF(&p->p_vu.p_object, argc); -+ (*argc) += 2; -+@@ -407,9 +504,11 @@ dumpAMF(AMFObject *obj, char *ptr, AVal *argv, int *argc) -+ int i, ac = *argc; -+ const char opt[] = "NBSO Z"; -+ -+- for (i=0; i < obj->o_num; i++) -++ for (i = 0; i < obj->o_num; i++) -+ { -+ AMFObjectProperty *p = &obj->o_props[i]; -++ if ((p->p_type == AMF_ECMA_ARRAY) || (p->p_type == AMF_STRICT_ARRAY)) -++ p->p_type = AMF_OBJECT; -+ argv[ac].av_val = ptr+1; -+ argv[ac++].av_len = 2; -+ ptr += sprintf(ptr, " -C "); -+@@ -569,6 +668,7 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int -+ server->arglen += countAMF(&r->Link.extras, &server->argc); -+ } -+ SendConnectResult(r, txn); -++ SendCheckBWResponse(r, FALSE, TRUE); -+ } -+ else if (AVMATCH(&method, &av_createStream)) -+ { -+@@ -583,10 +683,26 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int -+ AVal usherToken; -+ AMFProp_GetString(AMF_GetProp(&obj, NULL, 3), &usherToken); -+ AVreplace(&usherToken, &av_dquote, &av_escdquote); -++#ifdef WIN32 -++ AVreplace(&usherToken, &av_caret, &av_esccaret); -++ AVreplace(&usherToken, &av_pipe, &av_escpipe); -++#endif -+ server->arglen += 6 + usherToken.av_len; -+ server->argc += 2; -+ r->Link.usherToken = usherToken; -+ } -++ else if (AVMATCH(&method, &av__checkbw)) -++ { -++ SendCheckBWResponse(r, TRUE, FALSE); -++ } -++ else if (AVMATCH(&method, &av_checkBandwidth)) -++ { -++ SendCheckBWResponse(r, FALSE, FALSE); -++ } -++ else if (AVMATCH(&method, &av_FCSubscribe)) -++ { -++ SendOnFCSubscribe(r); -++ } -+ else if (AVMATCH(&method, &av_play)) -+ { -+ char *file, *p, *q, *cmd, *ptr; -+@@ -602,6 +718,17 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int -+ if (obj.o_num > 5) -+ r->Link.length = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 5)); -+ */ -++ double StartFlag = 0; -++ AMFObjectProperty *Start = AMF_GetProp(&obj, NULL, 4); -++ if (!(Start->p_type == AMF_INVALID)) -++ StartFlag = AMFProp_GetNumber(Start); -++ r->Link.app = AVcopy(r->Link.app); -++ if (StartFlag == -1000 || (r->Link.app.av_val && strstr(r->Link.app.av_val, "live"))) -++ { -++ StartFlag = -1000; -++ server->arglen += 7; -++ server->argc += 1; -++ } -+ if (r->Link.tcUrl.av_len) -+ { -+ len = server->arglen + r->Link.playpath.av_len + 4 + -+@@ -619,6 +746,7 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int -+ argv[argc].av_val = ptr + 1; -+ argv[argc++].av_len = 2; -+ argv[argc].av_val = ptr + 5; -++ r->Link.tcUrl = StripParams(&r->Link.tcUrl); -+ ptr += sprintf(ptr," -r \"%s\"", r->Link.tcUrl.av_val); -+ argv[argc++].av_len = r->Link.tcUrl.av_len; -+ -+@@ -643,6 +771,7 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int -+ argv[argc].av_val = ptr + 1; -+ argv[argc++].av_len = 2; -+ argv[argc].av_val = ptr + 5; -++ r->Link.swfUrl = StripParams(&r->Link.swfUrl); -+ ptr += sprintf(ptr, " -W \"%s\"", r->Link.swfUrl.av_val); -+ argv[argc++].av_len = r->Link.swfUrl.av_len; -+ } -+@@ -665,10 +794,17 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int -+ r->Link.usherToken.av_val = NULL; -+ r->Link.usherToken.av_len = 0; -+ } -+- if (r->Link.extras.o_num) { -+- ptr = dumpAMF(&r->Link.extras, ptr, argv, &argc); -+- AMF_Reset(&r->Link.extras); -+- } -++ if (StartFlag == -1000) -++ { -++ argv[argc].av_val = ptr + 1; -++ argv[argc++].av_len = 6; -++ ptr += sprintf(ptr, " --live"); -++ } -++ if (r->Link.extras.o_num) -++ { -++ ptr = dumpAMF(&r->Link.extras, ptr, argv, &argc); -++ AMF_Reset(&r->Link.extras); -++ } -+ argv[argc].av_val = ptr + 1; -+ argv[argc++].av_len = 2; -+ argv[argc].av_val = ptr + 5; -+@@ -676,7 +812,13 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int -+ r->Link.playpath.av_len, r->Link.playpath.av_val); -+ argv[argc++].av_len = r->Link.playpath.av_len; -+ -+- av = r->Link.playpath; -++ if (r->Link.playpath.av_len) -++ av = r->Link.playpath; -++ else -++ { -++ av.av_val = "file"; -++ av.av_len = 4; -++ } -+ /* strip trailing URL parameters */ -+ q = memchr(av.av_val, '?', av.av_len); -+ if (q) -+@@ -710,25 +852,82 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int -+ -+ memcpy(file, av.av_val, av.av_len); -+ file[av.av_len] = '\0'; -+- for (p=file; *p; p++) -+- if (*p == ':') -+- *p = '_'; -+ -+- /* Add extension if none present */ -+- if (file[av.av_len - 4] != '.') -+- { -+- av.av_len += 4; -+- } -+- /* Always use flv extension, regardless of original */ -+- if (strcmp(file+av.av_len-4, ".flv")) -+- { -+- strcpy(file+av.av_len-4, ".flv"); -+- } -++ if (strlen(file) < 128) -++ { -++ /* Add extension if none present */ -++ if (file[av.av_len - 4] != '.') -++ { -++ av.av_len += 4; -++ } -++ -++ /* Always use flv extension, regardless of original */ -++ if (strcmp(file + av.av_len - 4, ".flv")) -++ { -++ strcpy(file + av.av_len - 4, ".flv"); -++ } -++ -++ /* Remove invalid characters from filename */ -++ file = strreplace(file, 0, ":", "_", TRUE); -++ file = strreplace(file, 0, "&", "_", TRUE); -++ file = strreplace(file, 0, "^", "_", TRUE); -++ file = strreplace(file, 0, "|", "_", TRUE); -++ } -++ else -++ { -++ /* Filename too long - generate unique name */ -++ strcpy(file, "vXXXXXX"); -++ mkstemp(file); -++ strcat(file, ".flv"); -++ } -++ -++ /* Add timestamp to the filename */ -++ char *filename, *pfilename, timestamp[21]; -++ int filename_len, timestamp_len; -++ time_t current_time; -++ -++ time(¤t_time); -++ timestamp_len = strftime(×tamp[0], sizeof (timestamp), "%Y-%m-%d_%I-%M-%S_", localtime(¤t_time)); -++ timestamp[timestamp_len] = '\0'; -++ filename_len = strlen(file); -++ filename = malloc(timestamp_len + filename_len + 1); -++ pfilename = filename; -++ memcpy(pfilename, timestamp, timestamp_len); -++ pfilename += timestamp_len; -++ memcpy(pfilename, file, filename_len); -++ pfilename += filename_len; -++ *pfilename++ = '\0'; -++ file = filename; -++ -+ argv[argc].av_val = ptr + 1; -+ argv[argc++].av_len = 2; -+ argv[argc].av_val = file; -+ argv[argc].av_len = av.av_len; -+- ptr += sprintf(ptr, " -o %s", file); -++#ifdef VLC -++ char *vlc; -++ int didAlloc = FALSE; -++ -++ if (getenv("VLC")) -++ vlc = getenv("VLC"); -++ else if (getenv("ProgramFiles")) -++ { -++ vlc = malloc(512 * sizeof (char)); -++ didAlloc = TRUE; -++ char *ProgramFiles = getenv("ProgramFiles"); -++ sprintf(vlc, "\"%s%s", ProgramFiles, " (x86)\\VideoLAN\\VLC\\vlc.exe"); -++ if (!file_exists(vlc + 1)) -++ sprintf(vlc + 1, "%s%s", ProgramFiles, "\\VideoLAN\\VLC\\vlc.exe"); -++ strcpy(vlc + strlen(vlc), "\" -"); -++ } -++ else -++ vlc = "vlc -"; -++ -++ ptr += sprintf(ptr, " | %s", vlc); -++ if (didAlloc) -++ free(vlc); -++#else -++ ptr += sprintf(ptr, " -o \"%s\"", file); -++#endif -+ now = RTMP_GetTime(); -+ if (now - server->filetime < DUPTIME && AVMATCH(&argv[argc], &server->filename)) -+ { -+@@ -742,7 +941,21 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int -+ server->filetime = now; -+ free(server->filename.av_val); -+ server->filename = argv[argc++]; -+- spawn_dumper(argc, argv, cmd); -++#ifdef VLC -++ FILE *vlc_cmdfile = fopen("VLC.bat", "w"); -++ char *vlc_batchcmd = strreplace(cmd, 0, "%", "%%", FALSE); -++ fprintf(vlc_cmdfile, "%s\n", vlc_batchcmd); -++ fclose(vlc_cmdfile); -++ free(vlc_batchcmd); -++ spawn_dumper(argc, argv, "VLC.bat"); -++#else -++ spawn_dumper(argc, argv, cmd); -++#endif -++ -++ /* Save command to text file */ -++ FILE *cmdfile = fopen("Command.txt", "a"); -++ fprintf(cmdfile, "%s\n", cmd); -++ fclose(cmdfile); -+ } -+ -+ free(cmd); -+@@ -861,12 +1074,18 @@ controlServerThread(void *unused) -+ { -+ case 'q': -+ RTMP_LogPrintf("Exiting\n"); -+- stopStreaming(rtmpServer); -+- exit(0); -++ if (rtmpServer) -++ stopStreaming(rtmpServer); -+ break; -+ default: -+ RTMP_LogPrintf("Unknown command \'%c\', ignoring\n", ich); -+ } -++ sleep(1); -++ if (rtmpServer && (rtmpServer->state == STREAMING_STOPPED)) -++ { -++ RTMP_Log(RTMP_LOGDEBUG, "Exiting text UI thread"); -++ break; -++ } -+ } -+ TFRET(); -+ } -+@@ -1054,7 +1273,6 @@ stopStreaming(STREAMING_SERVER * server) -+ } -+ } -+ -+- -+ void -+ sigIntHandler(int sig) -+ { -+@@ -1191,3 +1409,15 @@ AVreplace(AVal *src, const AVal *orig, const AVal *repl) -+ src->av_val = dest; -+ src->av_len = dptr - dest; -+ } -++ -++int -++file_exists(const char *fname) -++{ -++ FILE *file; -++ if ((file = fopen(fname, "r"))) -++ { -++ fclose(file); -++ return TRUE; -++ } -++ return FALSE; -++} -+diff --git rtmpsuck.c rtmpsuck.c -+index e886179..0abdba4 100644 -+--- rtmpsuck.c -++++ rtmpsuck.c -+@@ -25,10 +25,13 @@ -+ */ -+ -+ #include <stdlib.h> -++#ifdef __MINGW_H -++#include <unistd.h> -++#endif -+ #include <string.h> -+ #include <math.h> -+ #include <limits.h> -+- -++#include <time.h> -+ #include <signal.h> -+ #include <getopt.h> -+ -+@@ -141,18 +144,21 @@ SAVC(code); -+ SAVC(secureToken); -+ SAVC(onStatus); -+ SAVC(close); -++SAVC(play2); -+ static const AVal av_NetStream_Failed = AVC("NetStream.Failed"); -+ static const AVal av_NetStream_Play_Failed = AVC("NetStream.Play.Failed"); -+-static const AVal av_NetStream_Play_StreamNotFound = -+-AVC("NetStream.Play.StreamNotFound"); -+-static const AVal av_NetConnection_Connect_InvalidApp = -+-AVC("NetConnection.Connect.InvalidApp"); -++static const AVal av_NetStream_Play_StreamNotFound = AVC("NetStream.Play.StreamNotFound"); -++static const AVal av_NetConnection_Connect_InvalidApp = AVC("NetConnection.Connect.InvalidApp"); -++static const AVal av_NetConnection_Connect_Rejected = AVC("NetConnection.Connect.Rejected"); -+ static const AVal av_NetStream_Play_Start = AVC("NetStream.Play.Start"); -+ static const AVal av_NetStream_Play_Complete = AVC("NetStream.Play.Complete"); -+ static const AVal av_NetStream_Play_Stop = AVC("NetStream.Play.Stop"); -++static const AVal av_NetStream_Authenticate_UsherToken = AVC("NetStream.Authenticate.UsherToken"); -+ -+ static const char *cst[] = { "client", "server" }; -+ -++char *dumpAMF(AMFObject *obj, char *ptr); -++ -+ // Returns 0 for OK/Failed/error, 1 for 'Stop or Complete' -+ int -+ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *body) -+@@ -198,26 +204,28 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b -+ if (cobj.o_props[i].p_type == AMF_STRING) -+ { -+ pval = cobj.o_props[i].p_vu.p_aval; -+- RTMP_LogPrintf("%.*s: %.*s\n", pname.av_len, pname.av_val, pval.av_len, pval.av_val); -++ RTMP_LogPrintf("%10.*s : %.*s\n", pname.av_len, pname.av_val, pval.av_len, pval.av_val); -+ } -+ if (AVMATCH(&pname, &av_app)) -+ { -+- server->rc.Link.app = pval; -++ server->rc.Link.app = AVcopy(pval); -+ pval.av_val = NULL; -+ } -+ else if (AVMATCH(&pname, &av_flashVer)) -+ { -+- server->rc.Link.flashVer = pval; -++ server->rc.Link.flashVer = AVcopy(pval); -+ pval.av_val = NULL; -+ } -+ else if (AVMATCH(&pname, &av_swfUrl)) -+ { -+ #ifdef CRYPTO -+ if (pval.av_val) -+- RTMP_HashSWF(pval.av_val, &server->rc.Link.SWFSize, -+- (unsigned char *)server->rc.Link.SWFHash, 30); -++ { -++ AVal swfUrl = StripParams(&pval); -++ RTMP_HashSWF(swfUrl.av_val, &server->rc.Link.SWFSize, (unsigned char *) server->rc.Link.SWFHash, 30); -++ } -+ #endif -+- server->rc.Link.swfUrl = pval; -++ server->rc.Link.swfUrl = AVcopy(pval); -+ pval.av_val = NULL; -+ } -+ else if (AVMATCH(&pname, &av_tcUrl)) -+@@ -225,7 +233,7 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b -+ char *r1 = NULL, *r2; -+ int len; -+ -+- server->rc.Link.tcUrl = pval; -++ server->rc.Link.tcUrl = AVcopy(pval); -+ if ((pval.av_val[0] | 0x40) == 'r' && -+ (pval.av_val[1] | 0x40) == 't' && -+ (pval.av_val[2] | 0x40) == 'm' && -+@@ -267,7 +275,7 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b -+ } -+ else if (AVMATCH(&pname, &av_pageUrl)) -+ { -+- server->rc.Link.pageUrl = pval; -++ server->rc.Link.pageUrl = AVcopy(pval); -+ pval.av_val = NULL; -+ } -+ else if (AVMATCH(&pname, &av_audioCodecs)) -+@@ -287,14 +295,21 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b -+ if (pval.av_val) -+ free(pval.av_val); -+ } -++ -+ if (obj.o_num > 3) -+ { -+- if (AMFProp_GetBoolean(&obj.o_props[3])) -+- server->rc.Link.lFlags |= RTMP_LF_AUTH; -+- if (obj.o_num > 4) -+- { -+- AMFProp_GetString(&obj.o_props[4], &server->rc.Link.auth); -+- } -++ int i = obj.o_num - 3; -++ server->rc.Link.extras.o_num = i; -++ server->rc.Link.extras.o_props = malloc(i * sizeof (AMFObjectProperty)); -++ memcpy(server->rc.Link.extras.o_props, obj.o_props + 3, i * sizeof (AMFObjectProperty)); -++ obj.o_num = 3; -++ } -++ -++ if (server->rc.Link.extras.o_num) -++ { -++ server->rc.Link.Extras.av_val = calloc(2048, sizeof (char)); -++ dumpAMF(&server->rc.Link.extras, server->rc.Link.Extras.av_val); -++ server->rc.Link.Extras.av_len = strlen(server->rc.Link.Extras.av_val); -+ } -+ -+ if (!RTMP_Connect(&server->rc, pack)) -+@@ -303,6 +318,37 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b -+ return 1; -+ } -+ server->rc.m_bSendCounter = FALSE; -++ -++ if (server->rc.Link.extras.o_props) -++ { -++ AMF_Reset(&server->rc.Link.extras); -++ } -++ } -++ else if (AVMATCH(&method, &av_NetStream_Authenticate_UsherToken)) -++ { -++ AVal usherToken = {0}; -++ AMFProp_GetString(AMF_GetProp(&obj, NULL, 3), &usherToken); -++ server->rc.Link.usherToken = AVcopy(usherToken); -++ RTMP_LogPrintf("%10s : %.*s\n", "usherToken", server->rc.Link.usherToken.av_len, server->rc.Link.usherToken.av_val); -++ } -++ else if (AVMATCH(&method, &av_play2)) -++ { -++ RTMP_Log(RTMP_LOGDEBUG, "%s: Detected play2 request\n", __FUNCTION__); -++ if (body && nBodySize > 0) -++ { -++ char* pCmd = (char*) body; -++ char* pEnd = pCmd + nBodySize - 4; -++ while (pCmd < pEnd) -++ { -++ if (pCmd[0] == 'p' && pCmd[1] == 'l' && pCmd[2] == 'a' && pCmd[3] == 'y' && pCmd[4] == '2') -++ { -++ /* Disable bitrate transition by sending invalid command */ -++ pCmd[4] = 'z'; -++ break; -++ } -++ ++pCmd; -++ } -++ } -+ } -+ else if (AVMATCH(&method, &av_play)) -+ { -+@@ -323,6 +369,14 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b -+ if (!av.av_val) -+ goto out; -+ -++ double StartFlag = 0; -++ AMFObjectProperty *Start = AMF_GetProp(&obj, NULL, 4); -++ if (!(Start->p_type == AMF_INVALID)) -++ StartFlag = AMFProp_GetNumber(Start); -++ if (StartFlag == -1000 || (server->rc.Link.app.av_val && strstr(server->rc.Link.app.av_val, "live"))) -++ StartFlag = -1000; -++ RTMP_LogPrintf("%10s : %s\n", "live", (StartFlag == -1000) ? "yes" : "no"); -++ -+ /* check for duplicates */ -+ for (fl = server->f_head; fl; fl=fl->f_next) -+ { -+@@ -362,19 +416,104 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b -+ /* hope there aren't more than 255 dups */ -+ if (count) -+ flen += 2; -+- file = malloc(flen+1); -++ file = malloc(flen + 5); -+ -+ memcpy(file, av.av_val, av.av_len); -+ if (count) -+ sprintf(file+av.av_len, "%02x", count); -+ else -+ file[av.av_len] = '\0'; -+- for (p=file; *p; p++) -+- if (*p == ':') -+- *p = '_'; -+- RTMP_LogPrintf("Playpath: %.*s\nSaving as: %s\n", -+- server->rc.Link.playpath.av_len, server->rc.Link.playpath.av_val, -+- file); -++ -++ if (strlen(file) < 128) -++ { -++ /* Add extension if none present */ -++ if (file[av.av_len - 4] != '.') -++ { -++ av.av_len += 4; -++ } -++ -++ /* Always use flv extension, regardless of original */ -++ if (strcmp(file + av.av_len - 4, ".flv")) -++ { -++ strcpy(file + av.av_len - 4, ".flv"); -++ } -++ -++ /* Remove invalid characters from filename */ -++ file = strreplace(file, 0, ":", "_", TRUE); -++ file = strreplace(file, 0, "&", "_", TRUE); -++ file = strreplace(file, 0, "^", "_", TRUE); -++ file = strreplace(file, 0, "|", "_", TRUE); -++ } -++ else -++ { -++ /* Filename too long - generate unique name */ -++ strcpy(file, "vXXXXXX"); -++ mkstemp(file); -++ strcat(file, ".flv"); -++ } -++ -++ /* Add timestamp to the filename */ -++ char *filename, *pfilename, timestamp[21]; -++ int filename_len, timestamp_len; -++ time_t current_time; -++ -++ time(¤t_time); -++ timestamp_len = strftime(×tamp[0], sizeof (timestamp), "%Y-%m-%d_%I-%M-%S_", localtime(¤t_time)); -++ timestamp[timestamp_len] = '\0'; -++ filename_len = strlen(file); -++ filename = malloc(timestamp_len + filename_len + 1); -++ pfilename = filename; -++ memcpy(pfilename, timestamp, timestamp_len); -++ pfilename += timestamp_len; -++ memcpy(pfilename, file, filename_len); -++ pfilename += filename_len; -++ *pfilename++ = '\0'; -++ file = filename; -++ -++ RTMP_LogPrintf("%10s : %.*s\n%10s : %s\n", "Playpath", server->rc.Link.playpath.av_len, -++ server->rc.Link.playpath.av_val, "Saving as", file); -++ -++ /* Save command to text file */ -++ char *cmd = NULL, *ptr = NULL; -++ AVal swfUrl, tcUrl; -++ -++ cmd = calloc(4096, sizeof (char)); -++ ptr = cmd; -++ tcUrl = StripParams(&server->rc.Link.tcUrl); -++ swfUrl = StripParams(&server->rc.Link.swfUrl); -++ ptr += sprintf(ptr, "rtmpdump -r \"%.*s\" -a \"%.*s\" -f \"%.*s\" -W \"%.*s\" -p \"%.*s\"", -++ tcUrl.av_len, tcUrl.av_val, -++ server->rc.Link.app.av_len, server->rc.Link.app.av_val, -++ server->rc.Link.flashVer.av_len, server->rc.Link.flashVer.av_val, -++ swfUrl.av_len, swfUrl.av_val, -++ server->rc.Link.pageUrl.av_len, server->rc.Link.pageUrl.av_val); -++ -++ if (server->rc.Link.usherToken.av_val) -++ { -++ char *usherToken = strreplace(server->rc.Link.usherToken.av_val, server->rc.Link.usherToken.av_len, "\"", "\\\"", TRUE); -++#ifdef WIN32 -++ usherToken = strreplace(usherToken, 0, "^", "^^", TRUE); -++ usherToken = strreplace(usherToken, 0, "|", "^|", TRUE); -++#endif -++ ptr += sprintf(ptr, " --jtv \"%s\"", usherToken); -++ free(usherToken); -++ } -++ -++ if (server->rc.Link.Extras.av_len) -++ { -++ ptr += sprintf(ptr, "%.*s", server->rc.Link.Extras.av_len, server->rc.Link.Extras.av_val); -++ } -++ -++ if (StartFlag == -1000) -++ ptr += sprintf(ptr, "%s", " --live"); -++ ptr += sprintf(ptr, " -y \"%.*s\"", server->rc.Link.playpath.av_len, server->rc.Link.playpath.av_val); -++ ptr += sprintf(ptr, " -o \"%s\"\n", file); -++ -++ FILE *cmdfile = fopen("Command.txt", "a"); -++ fprintf(cmdfile, "%s", cmd); -++ fclose(cmdfile); -++ free(cmd); -++ -+ out = fopen(file, "wb"); -+ free(file); -+ if (!out) -+@@ -407,9 +546,10 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b -+ -+ RTMP_Log(RTMP_LOGDEBUG, "%s, onStatus: %s", __FUNCTION__, code.av_val); -+ if (AVMATCH(&code, &av_NetStream_Failed) -+- || AVMATCH(&code, &av_NetStream_Play_Failed) -+- || AVMATCH(&code, &av_NetStream_Play_StreamNotFound) -+- || AVMATCH(&code, &av_NetConnection_Connect_InvalidApp)) -++ || AVMATCH(&code, &av_NetStream_Play_Failed) -++ || AVMATCH(&code, &av_NetStream_Play_StreamNotFound) -++ || AVMATCH(&code, &av_NetConnection_Connect_Rejected) -++ || AVMATCH(&code, &av_NetConnection_Connect_InvalidApp)) -+ { -+ ret = 1; -+ } -+@@ -719,13 +859,18 @@ controlServerThread(void *unused) -+ { -+ case 'q': -+ RTMP_LogPrintf("Exiting\n"); -+- stopStreaming(rtmpServer); -+- free(rtmpServer); -+- exit(0); -++ if (rtmpServer) -++ stopStreaming(rtmpServer); -+ break; -+ default: -+ RTMP_LogPrintf("Unknown command \'%c\', ignoring\n", ich); -+ } -++ sleep(1); -++ if (rtmpServer && (rtmpServer->state == STREAMING_STOPPED)) -++ { -++ RTMP_Log(RTMP_LOGDEBUG, "Exiting text UI thread"); -++ break; -++ } -+ } -+ TFRET(); -+ } -+@@ -815,7 +960,7 @@ TFTYPE doServe(void *arg) // server socket and state (our listening socket) -+ -+ if (select(n + 1, &rfds, NULL, NULL, &tv) <= 0) -+ { -+- if (server->f_cur && server->rc.m_mediaChannel && !paused) -++ if (server->f_cur && server->rc.m_mediaChannel && !paused && server->rc.m_channelTimestamp) -+ { -+ server->rc.m_pauseStamp = server->rc.m_channelTimestamp[server->rc.m_mediaChannel]; -+ if (RTMP_ToggleStream(&server->rc)) -+@@ -1123,7 +1268,6 @@ stopStreaming(STREAMING_SERVER * server) -+ } -+ } -+ -+- -+ void -+ sigIntHandler(int sig) -+ { -+@@ -1196,3 +1340,48 @@ main(int argc, char **argv) -+ #endif -+ return nStatus; -+ } -++ -++char * -++dumpAMF(AMFObject *obj, char *ptr) -++{ -++ int i; -++ const char opt[] = "NBSO Z"; -++ -++ for (i = 0; i < obj->o_num; i++) -++ { -++ AMFObjectProperty *p = &obj->o_props[i]; -++ if ((p->p_type == AMF_ECMA_ARRAY) || (p->p_type == AMF_STRICT_ARRAY)) -++ p->p_type = AMF_OBJECT; -++ if (p->p_type > 5) -++ continue; -++ ptr += sprintf(ptr, " -C "); -++ if (p->p_name.av_val) -++ *ptr++ = 'N'; -++ *ptr++ = opt[p->p_type]; -++ *ptr++ = ':'; -++ if (p->p_name.av_val) -++ ptr += sprintf(ptr, "%.*s:", p->p_name.av_len, p->p_name.av_val); -++ switch (p->p_type) -++ { -++ case AMF_BOOLEAN: -++ *ptr++ = p->p_vu.p_number != 0 ? '1' : '0'; -++ break; -++ case AMF_STRING: -++ memcpy(ptr, p->p_vu.p_aval.av_val, p->p_vu.p_aval.av_len); -++ ptr += p->p_vu.p_aval.av_len; -++ break; -++ case AMF_NUMBER: -++ ptr += sprintf(ptr, "%f", p->p_vu.p_number); -++ break; -++ case AMF_OBJECT: -++ *ptr++ = '1'; -++ ptr = dumpAMF(&p->p_vu.p_object, ptr); -++ ptr += sprintf(ptr, " -C O:0"); -++ break; -++ case AMF_NULL: -++ default: -++ break; -++ } -++ } -++ return ptr; -++} -+diff --git thread.c thread.c -+index 0913c98..13d624a 100644 -+--- thread.c -++++ thread.c -+@@ -32,7 +32,7 @@ ThreadCreate(thrfunc *routine, void *args) -+ HANDLE thd; -+ -+ thd = (HANDLE) _beginthread(routine, 0, args); -+- if (thd == -1L) -++ if (thd == INVALID_HANDLE_VALUE) -+ RTMP_LogPrintf("%s, _beginthread failed with %d\n", __FUNCTION__, errno); -+ -+ return thd; -diff --git a/tools/depends/target/librtmp/UpdateToLatest.diff b/tools/depends/target/librtmp/UpdateToLatest.diff -new file mode 100644 -index 0000000000000000000000000000000000000000..d9d5f6b8e4869efaba4b03abef4ccb534c4e8beb ---- /dev/null -+++ b/tools/depends/target/librtmp/UpdateToLatest.diff -@@ -0,0 +1,257 @@ -+diff --git b/ChangeLog a/ChangeLog -+index c3b1a14..b027e31 100644 -+--- b/ChangeLog -++++ a/ChangeLog -+@@ -1,6 +1,6 @@ -+ RTMPDump -+ Copyright 2008-2009 Andrej Stepanchuk; Distributed under the GPL v2 -+-Copyright 2009-2011 Howard Chu -++Copyright 2009-2015 Howard Chu -+ Copyright 2009 The Flvstreamer Team -+ http://rtmpdump.mplayerhq.hu/ -+ -+diff --git b/librtmp/amf.c a/librtmp/amf.c -+index 73d1486..7954144 100644 -+--- b/librtmp/amf.c -++++ a/librtmp/amf.c -+@@ -33,6 +33,7 @@ -+ #include "bytes.h" -+ -+ static const AMFObjectProperty AMFProp_Invalid = { {0, 0}, AMF_INVALID }; -++static const AMFObject AMFObj_Invalid = { 0, 0 }; -+ static const AVal AV_empty = { 0, 0 }; -+ -+ /* Data is Big-Endian */ -+@@ -340,13 +341,19 @@ AMFProp_GetBoolean(AMFObjectProperty *prop) -+ void -+ AMFProp_GetString(AMFObjectProperty *prop, AVal *str) -+ { -+- *str = prop->p_vu.p_aval; -++ if (prop->p_type == AMF_STRING) -++ *str = prop->p_vu.p_aval; -++ else -++ *str = AV_empty; -+ } -+ -+ void -+ AMFProp_GetObject(AMFObjectProperty *prop, AMFObject *obj) -+ { -+- *obj = prop->p_vu.p_object; -++ if (prop->p_type == AMF_OBJECT) -++ *obj = prop->p_vu.p_object; -++ else -++ *obj = AMFObj_Invalid; -+ } -+ -+ int -+@@ -471,6 +478,8 @@ AMF3ReadString(const char *data, AVal *str) -+ RTMP_Log(RTMP_LOGDEBUG, -+ "%s, string reference, index: %d, not supported, ignoring!", -+ __FUNCTION__, refIndex); -++ str->av_val = NULL; -++ str->av_len = 0; -+ return len; -+ } -+ else -+@@ -510,9 +519,11 @@ AMF3Prop_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize, -+ if (name.av_len <= 0) -+ return nRes; -+ -++ nSize -= nRes; -++ if (nSize <= 0) -++ return -1; -+ prop->p_name = name; -+ pBuffer += nRes; -+- nSize -= nRes; -+ } -+ -+ /* decode */ -+@@ -598,6 +609,8 @@ AMF3Prop_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize, -+ __FUNCTION__, (unsigned char)(*pBuffer), pBuffer); -+ return -1; -+ } -++ if (nSize < 0) -++ return -1; -+ -+ return nOriginalSize - nSize; -+ } -+@@ -992,9 +1005,17 @@ AMF_DecodeArray(AMFObject *obj, const char *pBuffer, int nSize, -+ int nRes; -+ nArrayLen--; -+ -++ if (nSize <= 0) -++ { -++ bError = TRUE; -++ break; -++ } -+ nRes = AMFProp_Decode(&prop, pBuffer, nSize, bDecodeName); -+ if (nRes == -1) -+- bError = TRUE; -++ { -++ bError = TRUE; -++ break; -++ } -+ else -+ { -+ nSize -= nRes; -+@@ -1053,12 +1074,12 @@ AMF3_Decode(AMFObject *obj, const char *pBuffer, int nSize, int bAMFData) -+ else -+ { -+ int32_t classExtRef = (classRef >> 1); -+- int i; -++ int i, cdnum; -+ -+ cd.cd_externalizable = (classExtRef & 0x1) == 1; -+ cd.cd_dynamic = ((classExtRef >> 1) & 0x1) == 1; -+ -+- cd.cd_num = classExtRef >> 2; -++ cdnum = classExtRef >> 2; -+ -+ /* class name */ -+ -+@@ -1073,9 +1094,16 @@ AMF3_Decode(AMFObject *obj, const char *pBuffer, int nSize, int bAMFData) -+ cd.cd_name.av_val, cd.cd_externalizable, cd.cd_dynamic, -+ cd.cd_num); -+ -+- for (i = 0; i < cd.cd_num; i++) -++ for (i = 0; i < cdnum; i++) -+ { -+ AVal memberName; -++ if (nSize <=0) -++ { -++invalid: -++ RTMP_Log(RTMP_LOGDEBUG, "%s, invalid class encoding!", -++ __FUNCTION__); -++ return nOriginalSize; -++ } -+ len = AMF3ReadString(pBuffer, &memberName); -+ RTMP_Log(RTMP_LOGDEBUG, "Member: %s", memberName.av_val); -+ AMF3CD_AddProp(&cd, &memberName); -+@@ -1111,6 +1139,8 @@ AMF3_Decode(AMFObject *obj, const char *pBuffer, int nSize, int bAMFData) -+ int nRes, i; -+ for (i = 0; i < cd.cd_num; i++) /* non-dynamic */ -+ { -++ if (nSize <=0) -++ goto invalid; -+ nRes = AMF3Prop_Decode(&prop, pBuffer, nSize, FALSE); -+ if (nRes == -1) -+ RTMP_Log(RTMP_LOGDEBUG, "%s, failed to decode AMF3 property!", -+@@ -1128,6 +1158,8 @@ AMF3_Decode(AMFObject *obj, const char *pBuffer, int nSize, int bAMFData) -+ -+ do -+ { -++ if (nSize <=0) -++ goto invalid; -+ nRes = AMF3Prop_Decode(&prop, pBuffer, nSize, TRUE); -+ AMF_AddProp(obj, &prop); -+ -+@@ -1175,10 +1207,18 @@ AMF_Decode(AMFObject *obj, const char *pBuffer, int nSize, int bDecodeName) -+ -+ nRes = AMFProp_Decode(&prop, pBuffer, nSize, bDecodeName); -+ if (nRes == -1) -+- bError = TRUE; -++ { -++ bError = TRUE; -++ break; -++ } -+ else -+ { -+ nSize -= nRes; -++ if (nSize < 0) -++ { -++ bError = TRUE; -++ break; -++ } -+ pBuffer += nRes; -+ AMF_AddProp(obj, &prop); -+ } -+diff --git b/librtmp/log.c a/librtmp/log.c -+index 0012985..1b52000 100644 -+--- b/librtmp/log.c -++++ a/librtmp/log.c -+@@ -92,6 +92,10 @@ RTMP_LogLevel RTMP_LogGetLevel() -+ void RTMP_Log(int level, const char *format, ...) -+ { -+ va_list args; -++ -++ if ( level > RTMP_debuglevel ) -++ return; -++ -+ va_start(args, format); -+ cb(level, format, args); -+ va_end(args); -+diff --git b/librtmp/rtmp.c a/librtmp/rtmp.c -+index ca7db6a..a2863b0 100644 -+--- b/librtmp/rtmp.c -++++ a/librtmp/rtmp.c -+@@ -186,9 +186,12 @@ RTMPPacket_Reset(RTMPPacket *p) -+ } -+ -+ int -+-RTMPPacket_Alloc(RTMPPacket *p, int nSize) -++RTMPPacket_Alloc(RTMPPacket *p, uint32_t nSize) -+ { -+- char *ptr = calloc(1, nSize + RTMP_MAX_HEADER_SIZE); -++ char *ptr; -++ if (nSize > SIZE_MAX - RTMP_MAX_HEADER_SIZE) -++ return FALSE; -++ ptr = calloc(1, nSize + RTMP_MAX_HEADER_SIZE); -+ if (!ptr) -+ return FALSE; -+ p->m_body = ptr + RTMP_MAX_HEADER_SIZE; -+@@ -1180,7 +1183,7 @@ RTMP_GetNextMediaPacket(RTMP *r, RTMPPacket *packet) -+ while (!bHasMediaPacket && RTMP_IsConnected(r) -+ && RTMP_ReadPacket(r, packet)) -+ { -+- if (!RTMPPacket_IsReady(packet)) -++ if (!RTMPPacket_IsReady(packet) || !packet->m_nBodySize) -+ { -+ continue; -+ } -+@@ -3643,7 +3646,6 @@ RTMP_ReadPacket(RTMP *r, RTMPPacket *packet) -+ { -+ packet->m_nBodySize = AMF_DecodeInt24(header + 3); -+ packet->m_nBytesRead = 0; -+- RTMPPacket_Free(packet); -+ -+ if (nSize > 6) -+ { -+diff --git b/librtmp/rtmp.h a/librtmp/rtmp.h -+index 0248913..6d7dd89 100644 -+--- b/librtmp/rtmp.h -++++ a/librtmp/rtmp.h -+@@ -136,7 +136,7 @@ extern "C" -+ -+ void RTMPPacket_Reset(RTMPPacket *p); -+ void RTMPPacket_Dump(RTMPPacket *p); -+- int RTMPPacket_Alloc(RTMPPacket *p, int nSize); -++ int RTMPPacket_Alloc(RTMPPacket *p, uint32_t nSize); -+ void RTMPPacket_Free(RTMPPacket *p); -+ -+ #define RTMPPacket_IsReady(a) ((a)->m_nBytesRead == (a)->m_nBodySize) -+diff --git b/rtmpsrv.c a/rtmpsrv.c -+index a9e9045..5df4d3a 100644 -+--- b/rtmpsrv.c -++++ a/rtmpsrv.c -+@@ -404,10 +404,10 @@ countAMF(AMFObject *obj, int *argc) -+ static char * -+ dumpAMF(AMFObject *obj, char *ptr, AVal *argv, int *argc) -+ { -+- int i, len, ac = *argc; -++ int i, ac = *argc; -+ const char opt[] = "NBSO Z"; -+ -+- for (i=0, len=0; i < obj->o_num; i++) -++ for (i=0; i < obj->o_num; i++) -+ { -+ AMFObjectProperty *p = &obj->o_props[i]; -+ argv[ac].av_val = ptr+1; -+@@ -595,6 +595,8 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int -+ uint32_t now; -+ RTMPPacket pc = {0}; -+ AMFProp_GetString(AMF_GetProp(&obj, NULL, 3), &r->Link.playpath); -++ if (!r->Link.playpath.av_len) -++ return 0; -+ /* -+ r->Link.seekTime = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 4)); -+ if (obj.o_num > 5) -diff --git a/tools/depends/target/librtmp/libm.patch b/tools/depends/target/librtmp/libm.patch -deleted file mode 100644 -index d86485b584920d3b8e7d775196e50f9b7fe3b297..0000000000000000000000000000000000000000 ---- a/tools/depends/target/librtmp/libm.patch -+++ /dev/null -@@ -1,11 +0,0 @@ ----- Makefile.old 2013-06-04 17:35:58.000000000 +0200 --+++ Makefile 2013-06-04 17:36:13.000000000 +0200 --@@ -25,7 +25,7 @@ -- REQ_GNUTLS=gnutls -- REQ_OPENSSL=libssl,libcrypto -- LIBZ=-lz ---LIBS_posix= --+LIBS_posix=-lm -- LIBS_darwin= -- LIBS_mingw=-lws2_32 -lwinmm -lgdi32 -- LIB_GNUTLS=-lgnutls -lhogweed -lnettle -lgmp $(LIBZ) - -From 2c9b195f2c8cf3559bba7d7b21d35ee0d0bca59c Mon Sep 17 00:00:00 2001 +From a3fffaef5c155d74ff051a7bbb2c1b56449ece13 Mon Sep 17 00:00:00 2001 From: Claudio-Sjo <Claudio.Porfiri@gmail.com> Date: Mon, 16 Feb 2015 14:51:26 +0100 -Subject: [PATCH 23/67] - allow reads < CDIO_CD_FRAMESIZE_RAW by using a buffer +Subject: [PATCH 21/61] - allow reads < CDIO_CD_FRAMESIZE_RAW by using a buffer - fixes #15794 --- @@ -6615,10 +2149,10 @@ index 0427af4534bfe59a343f0518c7f4242d93299836..e99236294fa8b9b613e465a8ecaf3ad3 lsn_t m_lsnCurrent; // Position inside the track in logical sector number lsn_t m_lsnEnd; // End of m_iTrack in logical sector number -From d83b2890c3b4135d505f202f9081f59a1fd7b065 Mon Sep 17 00:00:00 2001 +From 60a1b2ccb05742807a0fcbceaf5da47c8c13a66f Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Fri, 24 Jun 2016 19:38:13 +0100 -Subject: [PATCH 24/67] codecoverlay: Include codec name in overlay +Subject: [PATCH 22/61] codecoverlay: Include codec name in overlay --- xbmc/cores/VideoPlayer/VideoPlayerAudio.cpp | 4 ++++ @@ -6644,7 +2178,7 @@ index 24228154ecf99911f74407d73d280778e6f98fcd..188b85b12b86f887324cdcfda3c3aa4c //print the inverse of the resample ratio, since that makes more sense //if the resample ratio is 0.5, then we're playing twice as fast diff --git a/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp b/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp -index fd260d4378f6b13a158a57a2493e59cbab1f7d9d..f6d1b8572c6a4a8b4a193ebfc9d36d85ccd2d819 100644 +index fee65c3bd9ccdb3b7fc6e677c0473dfdd3d131bc..11ffffb23b435b1ea77fc756cf321013393f9f4a 100644 --- a/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp +++ b/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp @@ -909,10 +909,13 @@ int CVideoPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts) @@ -6678,7 +2212,7 @@ index 1e5d2b98bbef15b47994c3e4735873a9946b58c7..d43350fa0eefb5960475a02c1327efc2 return s.str(); } diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -index 6efd0d51df46a530dd05b3add639f38a939cf92d..d61dc4f2668f8aca91bce79cfb631034061c491c 100644 +index f9fa18aa9dfea0d50be09947439e56219f1f9b3d..6cd7d243d0fbea08c33e81edb5a51ab402bd110d 100644 --- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp +++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp @@ -583,12 +583,14 @@ void OMXPlayerVideo::SetSpeed(int speed) @@ -6712,10 +2246,10 @@ index 0df7e72cc9d1947173c2bac5e72eb09976b51aa5..b5050081c360d29b1b478c27e6b88291 double m_iSubtitleDelay; bool m_bRenderSubs; -From e46e93d403ab9f6cb6f61a5b7ac39f347bcf6089 Mon Sep 17 00:00:00 2001 +From 34b921907166a74b1f941cb54e6437bbddc50e1e Mon Sep 17 00:00:00 2001 From: Anton Fedchin <afedchin@ruswizards.com> Date: Tue, 8 Mar 2016 21:20:58 +0300 -Subject: [PATCH 25/67] [DebugInfo] Add cpu usage info. +Subject: [PATCH 23/61] [DebugInfo] Add cpu usage info. --- .../VideoPlayer/VideoRenderers/DebugRenderer.cpp | 56 ++++++++-------------- @@ -6852,7 +2386,7 @@ index 85aefaace73994730f7d2bdff9de85c79e99b2a2..8005a13bc220be0c5c596d276197c11e }; \ No newline at end of file diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp -index 93f8d6f292accf34e153fa4d3dd982e5a4b4fded..db537d33a5d55fc856bbd3ec0a7846df3bb060be 100644 +index 558a1f3df9ac82f3c7f32a91a1f2235c7f6563c6..f2a133e1ff7b440ebc741878ccf87e6da090aa8c 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp +++ b/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp @@ -24,6 +24,7 @@ @@ -6863,7 +2397,7 @@ index 93f8d6f292accf34e153fa4d3dd982e5a4b4fded..db537d33a5d55fc856bbd3ec0a7846df #include "utils/log.h" #include "utils/StringUtils.h" #include "windowing/WindowingFactory.h" -@@ -926,7 +927,7 @@ void CRenderManager::Render(bool clear, DWORD flags, DWORD alpha, bool gui) +@@ -922,7 +923,7 @@ void CRenderManager::Render(bool clear, DWORD flags, DWORD alpha, bool gui) if (m_renderDebug) { @@ -6872,7 +2406,7 @@ index 93f8d6f292accf34e153fa4d3dd982e5a4b4fded..db537d33a5d55fc856bbd3ec0a7846df m_playerPort->GetDebugInfo(audio, video, player); -@@ -940,8 +941,10 @@ void CRenderManager::Render(bool clear, DWORD flags, DWORD alpha, bool gui) +@@ -936,8 +937,10 @@ void CRenderManager::Render(bool clear, DWORD flags, DWORD alpha, bool gui) missedvblanks, clockspeed - 100.0); } @@ -6885,10 +2419,10 @@ index 93f8d6f292accf34e153fa4d3dd982e5a4b4fded..db537d33a5d55fc856bbd3ec0a7846df m_debugTimer.Set(1000); -From e674b4137eb3ffe70a0bae619e24862ceae51b25 Mon Sep 17 00:00:00 2001 +From 5732950f2b9b5c9488bf669fc1dabfe773098900 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Fri, 22 May 2015 13:56:29 +0100 -Subject: [PATCH 26/67] ffmpeg: Allow neon to be enabled in unified builds +Subject: [PATCH 24/61] ffmpeg: Allow neon to be enabled in unified builds --- tools/depends/target/ffmpeg/Makefile | 4 ++++ @@ -6911,17 +2445,17 @@ index dffe2da1dfd09e06c5f15c362f7cbe3cf2a26f75..4081dddb6bc2db53559d35506cad6af4 ifeq ($(OS), linux) ffmpg_config += --target-os=$(OS) --cpu=$(CPU) -From c575384e34c27d1ffb70e0181e45bc4078b1d2ac Mon Sep 17 00:00:00 2001 +From 2bdca30180c30357bf1ad3f2266622acc44605a9 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Fri, 27 Feb 2015 14:37:27 +0000 -Subject: [PATCH 27/67] ffmpeg: Add some upstream HEVC optimisations +Subject: [PATCH 25/61] ffmpeg: Add some upstream HEVC optimisations --- tools/depends/target/ffmpeg/Makefile | 6 +- .../added_ARM_NEON_optimized_SAO_patches.patch | 3328 ++++++++++++++++++++ - tools/depends/target/ffmpeg/autobuild.sh | 3 + + tools/depends/target/ffmpeg/autobuild.sh | 2 + ...hevcdsp_ARM_NEON_optimized_epel_functions.patch | 409 +++ - 4 files changed, 3745 insertions(+), 1 deletion(-) + 4 files changed, 3744 insertions(+), 1 deletion(-) create mode 100644 tools/depends/target/ffmpeg/added_ARM_NEON_optimized_SAO_patches.patch create mode 100644 tools/depends/target/ffmpeg/hevcdsp_ARM_NEON_optimized_epel_functions.patch @@ -10284,16 +5818,15 @@ index 0000000000000000000000000000000000000000..792b5fea581613a6fe9108443357f975 +2.5.0 + diff --git a/tools/depends/target/ffmpeg/autobuild.sh b/tools/depends/target/ffmpeg/autobuild.sh -index 9c26b239c2b2c1221bed7c4d99c46e909a4a5c5d..b9590d7b200a2ccf0fe3aa660e3b08b82d2133fc 100755 +index e491c788793fa5df35e4570b54d7606183350376..1a169999f75813a3f8e18185ced0620d445dee1f 100755 --- a/tools/depends/target/ffmpeg/autobuild.sh +++ b/tools/depends/target/ffmpeg/autobuild.sh -@@ -128,6 +128,9 @@ cd "ffmpeg-${VERSION}" || exit 2 +@@ -128,6 +128,8 @@ cd "ffmpeg-${VERSION}" || exit 2 tar --strip-components=1 -xf $MYDIR/${ARCHIVE} - patch -p1 < ../../0001-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patch -+patch -p1 < ../../0001-Discard-data-before-VO-VOL-in-mpeg-4-over-mpegts.patch -+patch -p1 < ../../hevcdsp_ARM_NEON_optimized_epel_functions.patch -+patch -p1 < ../../added_ARM_NEON_optimized_SAO_patches.patch + patch -p1 < ../0001-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patch ++patch -p1 < ../hevcdsp_ARM_NEON_optimized_epel_functions.patch ++patch -p1 < ../added_ARM_NEON_optimized_SAO_patches.patch CFLAGS="$CFLAGS" CXXFLAGS="$CXXFLAGS" LDFLAGS="$LDFLAGS" \ ./configure --prefix=$FFMPEG_PREFIX \ @@ -10713,10 +6246,10 @@ index 0000000000000000000000000000000000000000..5e8e07d407f045fc99554f0f061d1e81 +2.5.0 + -From 641013389142290475c0c053cf2cbd3a4866eae0 Mon Sep 17 00:00:00 2001 +From 68dcdd8420309caf7e4f7896b5c27df98705590c Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Thu, 7 May 2015 14:04:18 +0100 -Subject: [PATCH 28/67] [ffmpeg] Add GPU acceleration to hevc +Subject: [PATCH 26/61] [ffmpeg] Add GPU acceleration to hevc --- tools/depends/target/ffmpeg/Makefile | 4 +- @@ -10748,14 +6281,14 @@ index d9db534dd8c59a4993a3509737d901fbb3923de8..2dc4addea504d142eb74385653584bf3 cd $(PLATFORM);\ CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" CPPFLAGS="$(CPPFLAGS)" LDFLAGS="$(LDFLAGS)" \ diff --git a/tools/depends/target/ffmpeg/autobuild.sh b/tools/depends/target/ffmpeg/autobuild.sh -index b9590d7b200a2ccf0fe3aa660e3b08b82d2133fc..b6bd57731bca6dfe5f814a4043b3e08d1bb08318 100755 +index 1a169999f75813a3f8e18185ced0620d445dee1f..e2641093d15e5b465fae7e5f87c3ea18573dd6ee 100755 --- a/tools/depends/target/ffmpeg/autobuild.sh +++ b/tools/depends/target/ffmpeg/autobuild.sh -@@ -131,6 +131,7 @@ patch -p1 < ../../0001-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patc - patch -p1 < ../../0001-Discard-data-before-VO-VOL-in-mpeg-4-over-mpegts.patch - patch -p1 < ../../hevcdsp_ARM_NEON_optimized_epel_functions.patch - patch -p1 < ../../added_ARM_NEON_optimized_SAO_patches.patch -+patch -p1 < ../../pfcd_hevc_optimisations.patch +@@ -130,6 +130,7 @@ tar --strip-components=1 -xf $MYDIR/${ARCHIVE} + patch -p1 < ../0001-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patch + patch -p1 < ../hevcdsp_ARM_NEON_optimized_epel_functions.patch + patch -p1 < ../added_ARM_NEON_optimized_SAO_patches.patch ++patch -p1 < ../pfcd_hevc_optimisations.patch CFLAGS="$CFLAGS" CXXFLAGS="$CXXFLAGS" LDFLAGS="$LDFLAGS" \ ./configure --prefix=$FFMPEG_PREFIX \ @@ -48902,10 +44435,10 @@ index 0000000000000000000000000000000000000000..e172ebf157aebffe1ae50b4a2b25fd71 +2.7.4 + -From 4dcf6adc09c509c7e448a4fcfe48bc7da6f907a8 Mon Sep 17 00:00:00 2001 +From 8d0b79d79bc31d6f84ee57e9b40b45dbe92be56d Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Sat, 22 Aug 2015 23:06:56 +0100 -Subject: [PATCH 29/67] [dvdmessage] Increase timeout on +Subject: [PATCH 27/61] [dvdmessage] Increase timeout on CDVDMsgGeneralSynchronize --- @@ -48913,23 +44446,23 @@ Subject: [PATCH 29/67] [dvdmessage] Increase timeout on 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xbmc/cores/VideoPlayer/DVDMessage.cpp b/xbmc/cores/VideoPlayer/DVDMessage.cpp -index 5aed6918d217df884107fe6366b3668efa96af20..2442fc808ae89c5550b8db34b2605f5037f2ef29 100644 +index 0dcc664fd862706c60659f3664c7d964597c94d5..7614c831af9dfc821121a4111546fd4dfc664d06 100644 --- a/xbmc/cores/VideoPlayer/DVDMessage.cpp +++ b/xbmc/cores/VideoPlayer/DVDMessage.cpp @@ -90,7 +90,7 @@ bool CDVDMsgGeneralSynchronize::Wait(unsigned int milliseconds, unsigned int sou - void CDVDMsgGeneralSynchronize::Wait(volatile bool *abort, unsigned int source) + void CDVDMsgGeneralSynchronize::Wait(std::atomic<bool>& abort, unsigned int source) { -- while(!Wait(100, source)) -+ while(!Wait(200, source)) - { - if(abort && *abort) - return; +- while(!Wait(100, source) && !abort); ++ while(!Wait(200, source) && !abort); + } + + long CDVDMsgGeneralSynchronize::Release() -From 01bce0b478e428f0e8805868222928e8274bb809 Mon Sep 17 00:00:00 2001 +From 3ccd3f7c40d9211b26df3479d89e931eb4ff3a95 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Wed, 16 Sep 2015 19:05:12 +0100 -Subject: [PATCH 30/67] [3d] Make MVC a valid 3D filename tag +Subject: [PATCH 28/61] [3d] Make MVC a valid 3D filename tag --- xbmc/guilib/StereoscopicsManager.cpp | 9 +++++++++ @@ -48958,10 +44491,10 @@ index b34873cba6534086ae243326550385867a03256a..1443acaf0f25df458ae49766e13dd032 } diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp -index 446293308010f3b8cd8d325fa6d0285fcc9f892d..ae21da29314ae8faa35129a79e62e82b55fbc306 100644 +index 03f566d3ee4eab690d2236b7739080269d552511..60e5652f69e96a559d8080e01dc214a56fb19343 100644 --- a/xbmc/settings/AdvancedSettings.cpp +++ b/xbmc/settings/AdvancedSettings.cpp -@@ -403,6 +403,7 @@ void CAdvancedSettings::Initialize() +@@ -402,6 +402,7 @@ void CAdvancedSettings::Initialize() m_stereoscopicregex_3d = "[-. _]3d[-. _]"; m_stereoscopicregex_sbs = "[-. _]h?sbs[-. _]"; m_stereoscopicregex_tab = "[-. _]h?tab[-. _]"; @@ -48969,7 +44502,7 @@ index 446293308010f3b8cd8d325fa6d0285fcc9f892d..ae21da29314ae8faa35129a79e62e82b m_useDisplayControlHWStereo = false; -@@ -517,6 +518,7 @@ void CAdvancedSettings::ParseSettingsFile(const std::string &file) +@@ -516,6 +517,7 @@ void CAdvancedSettings::ParseSettingsFile(const std::string &file) XMLUtils::GetString(pElement, "stereoscopicregex3d", m_stereoscopicregex_3d); XMLUtils::GetString(pElement, "stereoscopicregexsbs", m_stereoscopicregex_sbs); XMLUtils::GetString(pElement, "stereoscopicregextab", m_stereoscopicregex_tab); @@ -48978,10 +44511,10 @@ index 446293308010f3b8cd8d325fa6d0285fcc9f892d..ae21da29314ae8faa35129a79e62e82b XMLUtils::GetFloat(pElement, "audiodelayrange", m_videoAudioDelayRange, 10, 600); XMLUtils::GetString(pElement, "defaultplayer", m_videoDefaultPlayer); diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h -index bcbd5d1c68b576034a418dd2dce0b47071229e0b..d4a30863806eb1c86042e0991793aedf20bf8344 100644 +index 1727580c0c8de2b6fda19a741f90721a570b96b8..4fa973515df6e677418a6bf7f9d0b4a31c022c0a 100644 --- a/xbmc/settings/AdvancedSettings.h +++ b/xbmc/settings/AdvancedSettings.h -@@ -372,6 +372,7 @@ class CAdvancedSettings : public ISettingCallback, public ISettingsHandler +@@ -371,6 +371,7 @@ class CAdvancedSettings : public ISettingCallback, public ISettingsHandler std::string m_stereoscopicregex_3d; std::string m_stereoscopicregex_sbs; std::string m_stereoscopicregex_tab; @@ -48990,10 +44523,10 @@ index bcbd5d1c68b576034a418dd2dce0b47071229e0b..d4a30863806eb1c86042e0991793aedf bool m_useDisplayControlHWStereo; -From 6268ac7405bc4f407e486644d11383f30e48c952 Mon Sep 17 00:00:00 2001 +From 55dd622a6608b801350e62955c891a6a78a3e8e9 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Mon, 5 Oct 2015 14:58:05 +0100 -Subject: [PATCH 31/67] [3d] Swap top/bottom sides of GUI +Subject: [PATCH 29/61] [3d] Swap top/bottom sides of GUI --- xbmc/guilib/GraphicContext.cpp | 2 +- @@ -49013,10 +44546,10 @@ index 9caa43113f63139d277bd71242a858a581736845..3ace73527a7c359ac21c87bf38b5d648 } if(m_stereoMode == RENDER_STEREO_MODE_SPLIT_VERTICAL) -From 97e700d5324b40fc895f1cbcf656ad4291ecfbee Mon Sep 17 00:00:00 2001 +From 79e39f5976fccbf9e9699b60b4f45a5f59d19bb5 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Sun, 11 Oct 2015 20:51:37 +0100 -Subject: [PATCH 32/67] Revert "Revert "Disable extra logging by default"" +Subject: [PATCH 30/61] Revert "Revert "Disable extra logging by default"" This reverts commit a880554325be187b877cd8f0e2b338e7267da636. --- @@ -49024,10 +44557,10 @@ This reverts commit a880554325be187b877cd8f0e2b338e7267da636. 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/settings/settings.xml b/system/settings/settings.xml -index ca7e8892606782e54d4883c5b2f0e6686b1ae280..b67d1113477541f5ce3533495a9960b8646b83ed 100644 +index 88b67c1869246037e81fb3efbe293f9fee37d25e..df60cf2d052f5a1570bd445468b156211a870007 100644 --- a/system/settings/settings.xml +++ b/system/settings/settings.xml -@@ -2649,12 +2649,12 @@ +@@ -2672,12 +2672,12 @@ </setting> <setting id="debug.extralogging" type="boolean" label="666" help="36394"> <level>1</level> @@ -49043,32 +44576,32 @@ index ca7e8892606782e54d4883c5b2f0e6686b1ae280..b67d1113477541f5ce3533495a9960b8 <options>loggingcomponents</options> <delimiter>,</delimiter> -From 52605aac1a6ca5d9a77513d6467935e7795c540a Mon Sep 17 00:00:00 2001 +From e18e8f939792d196c85b36c1e65a0ec4bb00bfc3 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Thu, 26 Nov 2015 17:14:49 +0000 -Subject: [PATCH 33/67] [ae] Add debug logging showing resamplerate +Subject: [PATCH 31/61] [ae] Add debug logging showing resamplerate --- xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp -index 5bb87b2764fdf1606f438fb3a008b322f8adf271..f9e8a9beaa9b3b4590c698a4d64351cb14c2339d 100644 +index 5196c62cd005d6c52cd741fc523eb5b7cd4b625b..dc9a34059f0eca5287bf42a7a8f89910c35e84e3 100644 --- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp -@@ -2471,6 +2471,7 @@ CSampleBuffer* CActiveAE::SyncStream(CActiveAEStream *stream) - if (stream->m_resampleBuffers) +@@ -2451,6 +2451,7 @@ CSampleBuffer* CActiveAE::SyncStream(CActiveAEStream *stream) + if (stream->m_processingBuffers) { - stream->m_resampleBuffers->m_resampleRatio = stream->CalcResampleRatio(error); -+ CLog::Log(LOGDEBUG, "CDVDPlayerAudio::%s rr:%.5f error:%.6f", __FUNCTION__, stream->m_resampleBuffers->m_resampleRatio, error); + stream->m_processingBuffers->SetRR(stream->CalcResampleRatio(error)); ++ CLog::Log(LOGDEBUG, "CDVDPlayerAudio::%s rr:%.5f error:%.6f", __FUNCTION__, stream->m_processingBuffers->GetRR(), error); } } - else if (stream->m_resampleBuffers) + else if (stream->m_processingBuffers) -From 17b01a2c74a918d1d6fddc35d7b3a7da986d7225 Mon Sep 17 00:00:00 2001 +From 83909d8961c984556768c161a0d2db8ff88e271b Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Mon, 21 Dec 2015 22:17:25 +0000 -Subject: [PATCH 34/67] [omximage] Fall back to arm jpeg encode/decode when gpu +Subject: [PATCH 32/61] [omximage] Fall back to arm jpeg encode/decode when gpu is busy --- @@ -49311,10 +44844,10 @@ index a93aa82663903fb1bf712058c2e259290ee742e6..6f38dbc7e5cc721c59a3633935f08218 extern COMXImage g_OMXImage; -From 95d0673204e2559173405d03df038ac152a5501b Mon Sep 17 00:00:00 2001 +From 4eada6619f36a9cd27209354d2f771458a166dd4 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Wed, 9 Dec 2015 13:31:14 +0000 -Subject: [PATCH 35/67] [mmalcodec] Fail to open when width is invalid. Can +Subject: [PATCH 33/61] [mmalcodec] Fail to open when width is invalid. Can happen with mpegts files --- @@ -49322,10 +44855,10 @@ Subject: [PATCH 35/67] [mmalcodec] Fail to open when width is invalid. Can 1 file changed, 3 insertions(+) diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -index c0e553ca060749edff28bcbb880ed3e149b9f751..8691b086a46fcdd03eee809a53ea9b20f74dcc05 100644 +index c6f98ded45062617d88571cd70fc6336cfdc32c9..283b2626731c25c67e4c065dac7725a488c09523 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -@@ -541,6 +541,9 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) +@@ -368,6 +368,9 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) if (g_advancedSettings.CanLogComponent(LOGVIDEO)) CLog::Log(LOGDEBUG, "%s::%s usemmal:%d software:%d %dx%d renderer:%p", CLASSNAME, __func__, CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_USEMMAL), hints.software, hints.width, hints.height, options.m_opaque_pointer); @@ -49336,10 +44869,10 @@ index c0e553ca060749edff28bcbb880ed3e149b9f751..8691b086a46fcdd03eee809a53ea9b20 if (!CSettings::GetInstance().GetBool(CSettings::SETTING_VIDEOPLAYER_USEMMAL) || hints.software) return false; -From 9f2c6309ca9bcc281124fa0a5bdb665d9fb50f35 Mon Sep 17 00:00:00 2001 +From cad95d3b4d889687eab0da4da40549cbed5df09e Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Tue, 12 Jan 2016 16:29:57 +0000 -Subject: [PATCH 36/67] ffmpeg: Add cabac opimisations for hevc +Subject: [PATCH 34/61] ffmpeg: Add cabac opimisations for hevc --- .../0001-Squashed-commit-of-the-following.patch | 2179 ++++++++++++++++++++ @@ -51564,22 +47097,22 @@ index 2dc4addea504d142eb74385653584bf39b253156..d1d76cb2ce04d5fd056796cc133fceb3 cd $(PLATFORM);\ CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" CPPFLAGS="$(CPPFLAGS)" LDFLAGS="$(LDFLAGS)" \ diff --git a/tools/depends/target/ffmpeg/autobuild.sh b/tools/depends/target/ffmpeg/autobuild.sh -index b6bd57731bca6dfe5f814a4043b3e08d1bb08318..65800dfccc7cbf17124a96d81378b1c3ddf92342 100755 +index e2641093d15e5b465fae7e5f87c3ea18573dd6ee..7022b5fadef58ad27b61725d77131bd78af2f51d 100755 --- a/tools/depends/target/ffmpeg/autobuild.sh +++ b/tools/depends/target/ffmpeg/autobuild.sh -@@ -132,6 +132,7 @@ patch -p1 < ../../0001-Discard-data-before-VO-VOL-in-mpeg-4-over-mpegts.patch - patch -p1 < ../../hevcdsp_ARM_NEON_optimized_epel_functions.patch - patch -p1 < ../../added_ARM_NEON_optimized_SAO_patches.patch - patch -p1 < ../../pfcd_hevc_optimisations.patch -+patch -p1 < ../../0001-Squashed-commit-of-the-following.patch +@@ -131,6 +131,7 @@ patch -p1 < ../0001-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patch + patch -p1 < ../hevcdsp_ARM_NEON_optimized_epel_functions.patch + patch -p1 < ../added_ARM_NEON_optimized_SAO_patches.patch + patch -p1 < ../pfcd_hevc_optimisations.patch ++patch -p1 < ../0001-Squashed-commit-of-the-following.patch CFLAGS="$CFLAGS" CXXFLAGS="$CXXFLAGS" LDFLAGS="$LDFLAGS" \ ./configure --prefix=$FFMPEG_PREFIX \ -From 3dac5d0c77bfd3b88d90944154c058d1e6429bb8 Mon Sep 17 00:00:00 2001 +From ee0055a7424b344357a0a8dbcfc3524f841f31ff Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Fri, 19 Sep 2014 11:54:49 +0100 -Subject: [PATCH 37/67] [videoplayer/rbp] Add pi specific option to maintain +Subject: [PATCH 35/61] [videoplayer/rbp] Add pi specific option to maintain vsync with pll adjustment New A/V sync option in settings/video/playback to do "Adjust PLL". @@ -51601,10 +47134,10 @@ or drop/dupe audio packets which is normally required. 12 files changed, 122 insertions(+), 19 deletions(-) diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po -index 085e2a195d2e52ce6bea3ed791bf817f5be23b15..8cb9f8503c29c54cd0cb55018f867a45248c649f 100644 +index 3208dad8988fba4bce7687861037274a42ffd21f..b5ae4dc1a6b21ba96fd3498baff1b63004fa6902 100644 --- a/addons/resource.language.en_gb/resources/strings.po +++ b/addons/resource.language.en_gb/resources/strings.po -@@ -19417,3 +19417,35 @@ msgstr "" +@@ -19483,3 +19483,35 @@ msgstr "" msgctxt "#38190" msgid "Extract thumbnails from video files" msgstr "" @@ -51641,7 +47174,7 @@ index 085e2a195d2e52ce6bea3ed791bf817f5be23b15..8cb9f8503c29c54cd0cb55018f867a45 +msgid "Max" +msgstr "" diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml -index 737ec4e0c7f0feb98a6dd008b53e238c41dde8af..2e6c903df5e4d2cd064466db0ef55deada5cdc80 100644 +index 770c628a15304856504676af82d46d57c97b86b8..b7770ebc1b9568f9fe141d90a118b87106c86735 100644 --- a/system/settings/rbp.xml +++ b/system/settings/rbp.xml @@ -98,6 +98,20 @@ @@ -51666,7 +47199,7 @@ index 737ec4e0c7f0feb98a6dd008b53e238c41dde8af..2e6c903df5e4d2cd064466db0ef55dea <group id="3"> <setting id="audiooutput.ac3transcode" help="37024"> diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp -index f9e8a9beaa9b3b4590c698a4d64351cb14c2339d..6a22f8145ce9dfb46f0ddae27eb0753413b066d3 100644 +index dc9a34059f0eca5287bf42a7a8f89910c35e84e3..8cbc09c2401865f04d20662ddb24d52e78a6219d 100644 --- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp @@ -34,6 +34,10 @@ using namespace ActiveAE; @@ -51696,7 +47229,7 @@ index f9e8a9beaa9b3b4590c698a4d64351cb14c2339d..6a22f8145ce9dfb46f0ddae27eb07534 par->stream->m_resampleIntegral = 0.0; } return; -@@ -2466,7 +2471,16 @@ CSampleBuffer* CActiveAE::SyncStream(CActiveAEStream *stream) +@@ -2446,7 +2451,16 @@ CSampleBuffer* CActiveAE::SyncStream(CActiveAEStream *stream) if (!newerror || stream->m_syncState != CAESyncInfo::AESyncState::SYNC_INSYNC) return ret; @@ -51712,9 +47245,9 @@ index f9e8a9beaa9b3b4590c698a4d64351cb14c2339d..6a22f8145ce9dfb46f0ddae27eb07534 + } + else if (stream->m_resampleMode) { - if (stream->m_resampleBuffers) + if (stream->m_processingBuffers) { -@@ -3322,13 +3336,14 @@ void CActiveAE::SetStreamResampleRatio(CActiveAEStream *stream, double ratio) +@@ -3302,13 +3316,14 @@ void CActiveAE::SetStreamResampleRatio(CActiveAEStream *stream, double ratio) &msg, sizeof(MsgStreamParameter)); } @@ -51761,10 +47294,10 @@ index 2a31a6e3c09fa61907ef9e518158773ba7d3b03e..3efc7afc255c542ea2aedbf83d6962be void SetStreamFade(CActiveAEStream *stream, float from, float target, unsigned int millis); diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp -index 1d58691db79e53a4a4cfb32c45f209a115853722..d1e8863cb9600bf1a026520f77501bb98e51918a 100644 +index 430bbf65d5cd68927018d8d7d01c144185fcd7fb..f9a9825bfe3b037047bbb63e9aefd379c2cf40e9 100644 --- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp -@@ -503,11 +503,12 @@ void CActiveAEStream::SetResampleRatio(double ratio) +@@ -509,11 +509,12 @@ void CActiveAEStream::SetResampleRatio(double ratio) m_streamResampleRatio = ratio; } @@ -51781,10 +47314,10 @@ index 1d58691db79e53a4a4cfb32c45f209a115853722..d1e8863cb9600bf1a026520f77501bb9 void CActiveAEStream::SetFFmpegInfo(int profile, enum AVMatrixEncoding matrix_encoding, enum AVAudioServiceType audio_service_type) diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.h -index 0fd959b8071e5a03d7749689e2e0042907d4d4bf..8b25159f198279f2515fe4f84fc9403dcb46c401 100644 +index b44227aca644e6af5cf8f33ca92ee1028d180413..65a6c38d1040647ca86deca4193572d283de6868 100644 --- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.h +++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.h -@@ -137,7 +137,7 @@ public: +@@ -169,7 +169,7 @@ public: virtual double GetResampleRatio(); virtual void SetResampleRatio(double ratio); @@ -51793,7 +47326,7 @@ index 0fd959b8071e5a03d7749689e2e0042907d4d4bf..8b25159f198279f2515fe4f84fc9403d virtual void RegisterAudioCallback(IAudioCallback* pCallback); virtual void UnRegisterAudioCallback(); virtual void FadeVolume(float from, float to, unsigned int time); -@@ -154,6 +154,7 @@ protected: +@@ -186,6 +186,7 @@ protected: float m_streamAmplify; double m_streamResampleRatio; int m_streamResampleMode; @@ -51801,14 +47334,14 @@ index 0fd959b8071e5a03d7749689e2e0042907d4d4bf..8b25159f198279f2515fe4f84fc9403d unsigned int m_streamSpace; bool m_streamDraining; bool m_streamDrained; -@@ -194,6 +195,7 @@ protected: +@@ -226,6 +227,7 @@ protected: int m_fadingTime; int m_profile; int m_resampleMode; + float m_pllAdjust; double m_resampleIntegral; + double m_clockSpeed; enum AVMatrixEncoding m_matrixEncoding; - enum AVAudioServiceType m_audioServiceType; diff --git a/xbmc/cores/AudioEngine/Interfaces/AEStream.h b/xbmc/cores/AudioEngine/Interfaces/AEStream.h index 7416685ef766492b13bbbde9001f868f28907d34..e3dbc5f2ddd6269f5e80086d2fd04e1ae68ac828 100644 --- a/xbmc/cores/AudioEngine/Interfaces/AEStream.h @@ -51918,7 +47451,7 @@ index 188b85b12b86f887324cdcfda3c3aa4cd90d3a11..b05c4e4c6a2361455ab553133965aa20 if (!codec || codec->NeedPassthrough() == m_pAudioCodec->NeedPassthrough()) { // passthrough state has not changed diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp -index fbffa3a952d920cb41412f00f59d5c1c91f98740..d6591cc4e1938b231cd3ce9035ca9334dcffdde9 100644 +index 92f20e5174dd6b886cf622460ac68ab5f2fe24b9..3618a68143d30391f937eb4bfdb6ed09dd86b9ce 100644 --- a/xbmc/linux/RBP.cpp +++ b/xbmc/linux/RBP.cpp @@ -49,6 +49,7 @@ CRBP::CRBP() @@ -51975,10 +47508,10 @@ index 90b04db5405058be2ff20aeaa6af2d2ac651586f..084fba87f49f4c3b33a8dd4a20a626a3 void init_cursor(); void set_cursor(const void *pixels, int width, int height, int hotspot_x, int hotspot_y); -From d7f88d01cde2cd4b0894463321e1ff0c413d9446 Mon Sep 17 00:00:00 2001 +From dafa8df17474794163e7783cafecc1b9d5615e16 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Thu, 7 May 2015 15:35:43 +0100 -Subject: [PATCH 38/67] rbp: Support zero copy interface with hevc acceleration +Subject: [PATCH 36/61] rbp: Support zero copy interface with hevc acceleration --- xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp | 9 +++++++++ @@ -51986,10 +47519,10 @@ Subject: [PATCH 38/67] rbp: Support zero copy interface with hevc acceleration 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -index 967d5181a42f7cad0fe7b559a8eb958073a8144d..ec2d47d7443ab75af5ad119b8ae04fb072eca677 100644 +index 3ccf4b8cd92d9907653adda291d1124244963e1b..9216a91527478eb7f8a9062177596e9bb6319e52 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp -@@ -306,6 +306,15 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options +@@ -308,6 +308,15 @@ bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options if (tryhw && m_decoderState == STATE_NONE) { m_decoderState = STATE_HW_SINGLE; @@ -52006,12 +47539,12 @@ index 967d5181a42f7cad0fe7b559a8eb958073a8144d..ec2d47d7443ab75af5ad119b8ae04fb0 else { diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALFFmpeg.cpp -index 3825e4cca4df7e1a791410b741aecc64823a3c69..e1bb3ab37f68b69e39fb00ab6e4785a430250173 100644 +index ad0f65cc64f545b32d1812c9e218c57ec6866b00..a5597c1386c5afdc6ec8f6840355557ee26e8950 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALFFmpeg.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALFFmpeg.cpp -@@ -355,8 +355,9 @@ bool CDecoder::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture - assert(!picture->MMALBuffer->mmal_buffer); - picture->MMALBuffer->mmal_buffer = mmal_buffer; +@@ -281,8 +281,9 @@ bool CDecoder::GetPicture(AVCodecContext* avctx, AVFrame* frame, DVDVideoPicture + picture->MMALBuffer->mmal_buffer->data = (uint8_t *)gmem->m_vc_handle; + picture->MMALBuffer->mmal_buffer->alloc_size = picture->MMALBuffer->mmal_buffer->length = gmem->m_numbytes; - // need to flush ARM cache so GPU can see it - gmem->Flush(); @@ -52022,10 +47555,10 @@ index 3825e4cca4df7e1a791410b741aecc64823a3c69..e1bb3ab37f68b69e39fb00ab6e4785a4 if (g_advancedSettings.CanLogComponent(LOGVIDEO)) CLog::Log(LOGDEBUG, "%s::%s - mmal:%p dts:%.3f pts:%.3f buf:%p gpu:%p", CLASSNAME, __FUNCTION__, picture->MMALBuffer->mmal_buffer, 1e-6*picture->dts, 1e-6*picture->pts, picture->MMALBuffer, gmem); -From 2b6121f39768cf5d22ffc73a475484519ac2881e Mon Sep 17 00:00:00 2001 +From 340049d662e9165d55def43f8d09bee5376752a4 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Sat, 16 May 2015 18:26:04 +0100 -Subject: [PATCH 39/67] ffmpeg: use upstream mvc patches +Subject: [PATCH 37/61] ffmpeg: use upstream mvc patches --- ...vcodec-add-h264_mvc-codec-id-and-profiles.patch | 68 ++++++++++++ @@ -52260,16 +47793,16 @@ index d1d76cb2ce04d5fd056796cc133fceb3f3c246c9..92d9437b36eaa4e655990f7e68634e0b cd $(PLATFORM);\ CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" CPPFLAGS="$(CPPFLAGS)" LDFLAGS="$(LDFLAGS)" \ diff --git a/tools/depends/target/ffmpeg/autobuild.sh b/tools/depends/target/ffmpeg/autobuild.sh -index 65800dfccc7cbf17124a96d81378b1c3ddf92342..4217ea350aa93e4a7acbe9dd15c9f8699db383b8 100755 +index 7022b5fadef58ad27b61725d77131bd78af2f51d..0c323ac47f7f79f4ce786c29c8f58bccad5d96dd 100755 --- a/tools/depends/target/ffmpeg/autobuild.sh +++ b/tools/depends/target/ffmpeg/autobuild.sh -@@ -133,6 +133,9 @@ patch -p1 < ../../hevcdsp_ARM_NEON_optimized_epel_functions.patch - patch -p1 < ../../added_ARM_NEON_optimized_SAO_patches.patch - patch -p1 < ../../pfcd_hevc_optimisations.patch - patch -p1 < ../../0001-Squashed-commit-of-the-following.patch -+patch -p1 < ../../0001-avcodec-add-h264_mvc-codec-id-and-profiles.patch -+patch -p1 < ../../0001-h264_parser-add-support-for-parsing-h264-mvc-NALUs.patch -+patch -p1 < ../../h264_parser_fix_parsing_of_mvc_slices_in_some_corner_cases.patch +@@ -132,6 +132,9 @@ patch -p1 < ../hevcdsp_ARM_NEON_optimized_epel_functions.patch + patch -p1 < ../added_ARM_NEON_optimized_SAO_patches.patch + patch -p1 < ../pfcd_hevc_optimisations.patch + patch -p1 < ../0001-Squashed-commit-of-the-following.patch ++patch -p1 < ../0001-avcodec-add-h264_mvc-codec-id-and-profiles.patch ++patch -p1 < ../0001-h264_parser-add-support-for-parsing-h264-mvc-NALUs.patch ++patch -p1 < ../h264_parser_fix_parsing_of_mvc_slices_in_some_corner_cases.patch CFLAGS="$CFLAGS" CXXFLAGS="$CXXFLAGS" LDFLAGS="$LDFLAGS" \ ./configure --prefix=$FFMPEG_PREFIX \ @@ -52335,10 +47868,10 @@ index 0000000000000000000000000000000000000000..b39480ad098b9cd0882fcf75b96afb1b +2.7.4 + -From c2b0929d428aa4eb33d771121448a59e883c9842 Mon Sep 17 00:00:00 2001 +From 56c71f3a8e771ca8c61c4111b8622614f0f41bdb Mon Sep 17 00:00:00 2001 From: Anton Fedchin <afedchin@ruswizards.com> Date: Wed, 20 Jan 2016 17:02:16 +0300 -Subject: [PATCH 40/67] [VideoPlayer] DemuxFFmpeg: Properly demuxing h264_mvc +Subject: [PATCH 38/61] [VideoPlayer] DemuxFFmpeg: Properly demuxing h264_mvc streams. --- @@ -52346,7 +47879,7 @@ Subject: [PATCH 40/67] [VideoPlayer] DemuxFFmpeg: Properly demuxing h264_mvc 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -index 84310bbda6440dd10f9aa0711859f4dc0bb1fd1a..16e8e270b5a060bd174f794480a8b178a620d490 100644 +index c8ba4f869e844550e47ab9084aad1c59ba10f53a..1388a08c0403b0ab8942d4851ab97a229a9a777a 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp @@ -25,6 +25,7 @@ @@ -52357,7 +47890,7 @@ index 84310bbda6440dd10f9aa0711859f4dc0bb1fd1a..16e8e270b5a060bd174f794480a8b178 #include "DVDClock.h" // for DVD_TIME_BASE #include "DVDDemuxUtils.h" #include "DVDInputStreams/DVDInputStream.h" -@@ -1249,6 +1250,15 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) +@@ -1262,6 +1263,15 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) } case AVMEDIA_TYPE_VIDEO: { @@ -52373,7 +47906,7 @@ index 84310bbda6440dd10f9aa0711859f4dc0bb1fd1a..16e8e270b5a060bd174f794480a8b178 CDemuxStreamVideoFFmpeg* st = new CDemuxStreamVideoFFmpeg(this, pStream); stream = st; if(strcmp(m_pFormatContext->iformat->name, "flv") == 0) -@@ -1257,7 +1267,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) +@@ -1270,7 +1280,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) st->bVFR = false; // never trust pts in avi files with h264. @@ -52382,7 +47915,7 @@ index 84310bbda6440dd10f9aa0711859f4dc0bb1fd1a..16e8e270b5a060bd174f794480a8b178 st->bPTSInvalid = true; #if defined(AVFORMAT_HAS_STREAM_GET_R_FRAME_RATE) -@@ -1328,6 +1338,17 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) +@@ -1341,6 +1351,17 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) if (av_dict_get(pStream->metadata, "title", NULL, 0)) st->m_description = av_dict_get(pStream->metadata, "title", NULL, 0)->value; @@ -52401,10 +47934,10 @@ index 84310bbda6440dd10f9aa0711859f4dc0bb1fd1a..16e8e270b5a060bd174f794480a8b178 } case AVMEDIA_TYPE_DATA: -From 052ba44b0a0bd4736bc330c2f86e34cb8424ba60 Mon Sep 17 00:00:00 2001 +From 1cf1661ac0d3a7a9a8c29e695370f5f4b038cd9f Mon Sep 17 00:00:00 2001 From: Anton Fedchin <anightik@gmail.com> Date: Thu, 25 Feb 2016 11:21:25 +0300 -Subject: [PATCH 41/67] [Stereo3D] Added mvc modes. +Subject: [PATCH 39/61] [Stereo3D] Added mvc modes. --- xbmc/cores/VideoPlayer/VideoRenderers/RenderFlags.cpp | 4 ++++ @@ -52458,17 +47991,17 @@ index 1443acaf0f25df458ae49766e13dd0323454f2eb..6eb0752994bc5f8c47efbbf211120af0 i++; } -From 0bcb7f56f0fa79c4d7af4c64e0b931a997045d72 Mon Sep 17 00:00:00 2001 +From f64eab2d4da72fcf95e002dc26f3139e9550f690 Mon Sep 17 00:00:00 2001 From: Anton Fedchin <afedchin@ruswizards.com> Date: Sat, 23 Jan 2016 10:21:32 +0300 -Subject: [PATCH 42/67] [VideoPlayer] Fix possible wrong aspect. +Subject: [PATCH 40/61] [VideoPlayer] Fix possible wrong aspect. --- xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp b/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp -index f6d1b8572c6a4a8b4a193ebfc9d36d85ccd2d819..6b97183835ce7d614e8814cb065ac168947f5ce1 100644 +index 11ffffb23b435b1ea77fc756cf321013393f9f4a..63454775e1b8460afc2df1ab93633ec49156efd3 100644 --- a/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp +++ b/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp @@ -182,7 +182,7 @@ void CVideoPlayerVideo::OpenStream(CDVDStreamInfo &hint, CDVDVideoCodec* codec) @@ -52481,14 +48014,14 @@ index f6d1b8572c6a4a8b4a193ebfc9d36d85ccd2d819..6b97183835ce7d614e8814cb065ac168 else m_fForcedAspectRatio = 0.0; -From b409948c86ffdb3b000a82333be9c4ddeb45ddd7 Mon Sep 17 00:00:00 2001 +From e0dbe5d847499befef2382ee01f7f13438e4356e Mon Sep 17 00:00:00 2001 From: Anton Fedchin <afedchin@ruswizards.com> Date: Fri, 22 Jan 2016 18:18:33 +0300 -Subject: [PATCH 43/67] [VideoPlayer] DemuxFFmpeg: ssif remux +Subject: [PATCH 41/61] [VideoPlayer] DemuxFFmpeg: ssif remux --- project/VS2010Express/XBMC.vcxproj | 2 + - project/VS2010Express/XBMC.vcxproj.filters | 8 +- + project/VS2010Express/XBMC.vcxproj.filters | 6 + xbmc/cores/VideoPlayer/DVDDemuxers/CMakeLists.txt | 2 + .../VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp | 47 ++++++- .../cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.h | 2 + @@ -52496,15 +48029,15 @@ Subject: [PATCH 43/67] [VideoPlayer] DemuxFFmpeg: ssif remux .../VideoPlayer/DVDDemuxers/DVDDemuxStreamSSIF.h | 49 +++++++ xbmc/cores/VideoPlayer/DVDDemuxers/Makefile.in | 1 + xbmc/settings/AdvancedSettings.cpp | 2 +- - 9 files changed, 260 insertions(+), 9 deletions(-) + 9 files changed, 259 insertions(+), 8 deletions(-) create mode 100644 xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxStreamSSIF.cpp create mode 100644 xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxStreamSSIF.h diff --git a/project/VS2010Express/XBMC.vcxproj b/project/VS2010Express/XBMC.vcxproj -index 164b608f77e4848bda558daf44dede1fc18a8fb4..601c5848ab9bda32e90fced986cf61dad38800bf 100644 +index fc546b1efa6a8daf521a3bc44da62782603be5d8..1b5c0643fe18f61df6829a4eb33c9a82fd8468a4 100644 --- a/project/VS2010Express/XBMC.vcxproj +++ b/project/VS2010Express/XBMC.vcxproj -@@ -295,6 +295,7 @@ copy "..\Win32BuildSetup\dependencies\python27.dll" "$(TargetDir)"</Command> +@@ -296,6 +296,7 @@ copy "..\Win32BuildSetup\dependencies\python27.dll" "$(TargetDir)"</Command> <ClCompile Include="..\..\xbmc\cores\VideoPlayer\DVDDemuxers\DVDDemuxCDDA.cpp" /> <ClCompile Include="..\..\xbmc\cores\VideoPlayer\DVDDemuxers\DVDDemuxClient.cpp" /> <ClCompile Include="..\..\xbmc\cores\VideoPlayer\DVDDemuxers\DemuxMultiSource.cpp" /> @@ -52512,7 +48045,7 @@ index 164b608f77e4848bda558daf44dede1fc18a8fb4..601c5848ab9bda32e90fced986cf61da <ClCompile Include="..\..\xbmc\cores\VideoPlayer\DVDInputStreams\DVDInputStreamBluray.cpp" /> <ClCompile Include="..\..\xbmc\cores\VideoPlayer\DVDInputStreams\InputStreamMultiSource.cpp" /> <ClCompile Include="..\..\xbmc\cores\VideoPlayer\DVDInputStreams\DVDInputStreamPVRManager.cpp" /> -@@ -1069,6 +1070,7 @@ copy "..\Win32BuildSetup\dependencies\python27.dll" "$(TargetDir)"</Command> +@@ -1072,6 +1073,7 @@ copy "..\Win32BuildSetup\dependencies\python27.dll" "$(TargetDir)"</Command> <ClInclude Include="..\..\xbmc\cores\VideoPlayer\DVDDemuxers\DemuxMultiSource.h" /> <ClInclude Include="..\..\xbmc\cores\VideoPlayer\DVDDemuxers\DVDDemuxPacket.h" /> <ClInclude Include="..\..\xbmc\cores\VideoPlayer\Process\ProcessInfo.h" /> @@ -52521,10 +48054,10 @@ index 164b608f77e4848bda558daf44dede1fc18a8fb4..601c5848ab9bda32e90fced986cf61da <ClInclude Include="..\..\xbmc\cores\VideoPlayer\VideoRenderers\DebugRenderer.h" /> <ClInclude Include="..\..\xbmc\cores\VideoPlayer\VideoRenderers\HwDecRender\DXVAHD.h" /> diff --git a/project/VS2010Express/XBMC.vcxproj.filters b/project/VS2010Express/XBMC.vcxproj.filters -index b3c53788819764a400ea53e12440ba229735819c..b2d5230fdcd32f6db50e580f55cd7a63d4d19247 100644 +index ef911b1ce3b7d00674c332078584485de2dc49ae..0524f95c8549be034a3592b2c1909d688f0c9b17 100644 --- a/project/VS2010Express/XBMC.vcxproj.filters +++ b/project/VS2010Express/XBMC.vcxproj.filters -@@ -3452,6 +3452,9 @@ +@@ -3455,6 +3455,9 @@ <ClCompile Include="..\..\xbmc\dialogs\GUIDialogKeyboardTouch.cpp"> <Filter>dialogs</Filter> </ClCompile> @@ -52533,26 +48066,19 @@ index b3c53788819764a400ea53e12440ba229735819c..b2d5230fdcd32f6db50e580f55cd7a63 + </ClCompile> </ItemGroup> <ItemGroup> - <ClInclude Include="..\..\xbmc\win32\pch.h"> -@@ -6704,6 +6707,9 @@ - <ClInclude Include="..\..\xbmc\cores\AudioEngine\Engines\ActiveAE\AudioDSPAddons\ActiveAEDSP.h"> - <Filter>cores\AudioEngine\Engines\ActiveAE\AudioDSPAddons</Filter> + <ClInclude Include="..\..\xbmc\platform\win32\pch.h"> +@@ -6722,6 +6725,9 @@ + <ClInclude Include="..\..\xbmc\cores\AudioEngine\Engines\ActiveAE\ActiveAEFilter.h"> + <Filter>cores\AudioEngine\Engines\ActiveAE</Filter> </ClInclude> + <ClInclude Include="..\..\xbmc\cores\VideoPlayer\DVDDemuxers\DVDDemuxStreamSSIF.h"> + <Filter>cores\VideoPlayer\DVDDemuxers</Filter> + </ClInclude> </ItemGroup> <ItemGroup> - <ResourceCompile Include="..\..\xbmc\win32\XBMC_PC.rc"> -@@ -6790,4 +6796,4 @@ - <Filter>shaders</Filter> - </FxCompile> - </ItemGroup> --</Project> -\ No newline at end of file -+</Project> + <ResourceCompile Include="..\..\xbmc\platform\win32\XBMC_PC.rc"> diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/CMakeLists.txt b/xbmc/cores/VideoPlayer/DVDDemuxers/CMakeLists.txt -index 7d254f7650377485b909f26189d126455d49569a..65b369054c4ea329649a51f20f448394c70b110d 100644 +index 63776b1333bb66483303e44d6ebe60f3cd7e14d7..0da129ff99f57dc38ca8a854854d9fe658651e1f 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/CMakeLists.txt +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/CMakeLists.txt @@ -5,6 +5,7 @@ set(SOURCES DemuxMultiSource.cpp @@ -52572,7 +48098,7 @@ index 7d254f7650377485b909f26189d126455d49569a..65b369054c4ea329649a51f20f448394 DVDDemuxUtils.h DVDDemuxVobsub.h diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -index 16e8e270b5a060bd174f794480a8b178a620d490..4490b16318e1c54822cdbbf5fa6344d66c2fdbdd 100644 +index 1388a08c0403b0ab8942d4851ab97a229a9a777a..5775a82c37768bc585645ff5a8eb259c07ef9f9c 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp @@ -164,6 +164,7 @@ CDVDDemuxFFmpeg::CDVDDemuxFFmpeg() : CDVDDemux() @@ -52650,7 +48176,7 @@ index 16e8e270b5a060bd174f794480a8b178a620d490..4490b16318e1c54822cdbbf5fa6344d6 if (!stream) { CLog::Log(LOGERROR, "CDVDDemuxFFmpeg::AddStream - internal error, stream is null"); -@@ -1018,6 +1040,9 @@ bool CDVDDemuxFFmpeg::SeekTime(int time, bool backwords, double *startpts) +@@ -1023,6 +1045,9 @@ bool CDVDDemuxFFmpeg::SeekTime(int time, bool backwords, double *startpts) m_pkt.result = -1; av_packet_unref(&m_pkt.pkt); @@ -52660,7 +48186,7 @@ index 16e8e270b5a060bd174f794480a8b178a620d490..4490b16318e1c54822cdbbf5fa6344d6 CDVDInputStream::IPosTime* ist = m_pInput->GetIPosTime(); if (ist) { -@@ -1085,6 +1110,9 @@ bool CDVDDemuxFFmpeg::SeekByte(int64_t pos) +@@ -1098,6 +1123,9 @@ bool CDVDDemuxFFmpeg::SeekByte(int64_t pos) m_pkt.result = -1; av_packet_unref(&m_pkt.pkt); @@ -52670,7 +48196,7 @@ index 16e8e270b5a060bd174f794480a8b178a620d490..4490b16318e1c54822cdbbf5fa6344d6 return (ret >= 0); } -@@ -1252,11 +1280,12 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) +@@ -1265,11 +1293,12 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) { if (pStream->codec->codec_id == AV_CODEC_ID_H264_MVC) { @@ -52686,7 +48212,7 @@ index 16e8e270b5a060bd174f794480a8b178a620d490..4490b16318e1c54822cdbbf5fa6344d6 break; } CDemuxStreamVideoFFmpeg* st = new CDemuxStreamVideoFFmpeg(this, pStream); -@@ -1342,7 +1371,11 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) +@@ -1355,7 +1384,11 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) { if (CDVDCodecUtils::IsH264AnnexB(m_pFormatContext->iformat->name, pStream)) { @@ -52699,7 +48225,7 @@ index 16e8e270b5a060bd174f794480a8b178a620d490..4490b16318e1c54822cdbbf5fa6344d6 } else if (CDVDCodecUtils::ProcessH264MVCExtradata(pStream->codec->extradata, pStream->codec->extradata_size)) { -@@ -1435,7 +1468,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) +@@ -1448,7 +1481,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) if (langTag) strncpy(stream->language, langTag->value, 3); @@ -52958,10 +48484,10 @@ index e4f8aed0af96fe0dceec4d8517087742f2c7df81..f3b717ddabb4729fe0db5ebab5a7913b LIB = DVDDemuxers.a diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp -index ae21da29314ae8faa35129a79e62e82b55fbc306..8426b6c3f8f6af274e2990c8da323e4064db9b65 100644 +index 60e5652f69e96a559d8080e01dc214a56fb19343..cdaf53585a89a0da3a4038178806ee937049fe42 100644 --- a/xbmc/settings/AdvancedSettings.cpp +++ b/xbmc/settings/AdvancedSettings.cpp -@@ -392,7 +392,7 @@ void CAdvancedSettings::Initialize() +@@ -391,7 +391,7 @@ void CAdvancedSettings::Initialize() m_pictureExtensions = ".png|.jpg|.jpeg|.bmp|.gif|.ico|.tif|.tiff|.tga|.pcx|.cbz|.zip|.cbr|.rar|.rss|.webp|.jp2|.apng"; m_musicExtensions = ".nsv|.m4a|.flac|.aac|.strm|.pls|.rm|.rma|.mpa|.wav|.wma|.ogg|.mp3|.mp2|.m3u|.gdm|.imf|.m15|.sfx|.uni|.ac3|.dts|.cue|.aif|.aiff|.wpl|.ape|.mac|.mpc|.mp+|.mpp|.shn|.zip|.rar|.wv|.dsp|.xsp|.xwav|.waa|.wvs|.wam|.gcm|.idsp|.mpdsp|.mss|.spt|.rsd|.sap|.cmc|.cmr|.dmc|.mpt|.mpd|.rmt|.tmc|.tm8|.tm2|.oga|.url|.pxml|.tta|.rss|.wtv|.mka|.tak|.opus|.dff|.dsf"; @@ -52971,47 +48497,33 @@ index ae21da29314ae8faa35129a79e62e82b55fbc306..8426b6c3f8f6af274e2990c8da323e40 m_discStubExtensions = ".disc"; // internal music extensions -From ac2167deb4a7e8408903ca2aab446b3d0d954fa7 Mon Sep 17 00:00:00 2001 +From e2b43c6da9e7cdaba0c6f7d7bd59b36f3b6dc32f Mon Sep 17 00:00:00 2001 From: Anton Fedchin <afedchin@ruswizards.com> Date: Tue, 23 Feb 2016 16:01:08 +0300 -Subject: [PATCH 44/67] [libbluray] bump libbluray to 0.9.2-mvc. +Subject: [PATCH 42/61] [libbluray] bump libbluray to 0.9.2-mvc. --- project/BuildDependencies/scripts/0_package.list | 2 +- - xbmc/DllPaths_win32.h | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) + 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/BuildDependencies/scripts/0_package.list b/project/BuildDependencies/scripts/0_package.list -index 71024bfb7da48ddb033b159f83037319176229b4..2565d1d08f6591955266fcca3f1a8031db4379e4 100644 +index 2b6840102cdcaa464428694d16ac8d58e7c2d03f..4f3bddf0ef2e985986efffb97b9aeae5fa36d3e1 100644 --- a/project/BuildDependencies/scripts/0_package.list +++ b/project/BuildDependencies/scripts/0_package.list -@@ -16,7 +16,7 @@ freetype-2.4.6-win32-3.7z +@@ -17,7 +17,7 @@ freetype-2.6.3-win32-vc140.7z giflib-5.1.4-win32-vc140.7z jsonschemabuilder-1.0.0-win32-3.7z - libass-0.12.1-win32.7z --libbluray-0.8.1-win32-vc120.7z + libass-0.13.2-win32-vc140.7z +-libbluray-0.9.3-win32-vc140.7z +libbluray-0.9.2-mvc-win32-vc120.7z - libcdio-0.83-win32-2.7z - libcec-3.0.0-win32-2.7z - libexpat_2.0.1-win32.7z -diff --git a/xbmc/DllPaths_win32.h b/xbmc/DllPaths_win32.h -index 3748589f39b1f83f1e23e9eb4f64eddcf61cb030..ff34ff541049ad7d2fa5472c49e6412e0d68056b 100644 ---- a/xbmc/DllPaths_win32.h -+++ b/xbmc/DllPaths_win32.h -@@ -35,7 +35,7 @@ - #define DLL_PATH_LIBDVDNAV "special://xbmcbin/system/players/VideoPlayer/libdvdnav.dll" - - /* libbluray */ --#define DLL_PATH_LIBBLURAY "special://xbmcbin/system/players/dvdplayer/libbluray.dll" -+#define DLL_PATH_LIBBLURAY "special://xbmcbin/system/players/VideoPlayer/libbluray.dll" - - #endif - + libcdio-0.9.3-win32-vc140.7z + libcec-3.1.0-win32-vc140.7z + libfribidi-0.19.2-win32.7z -From 6bb5fcf3d003296bbe290c171577bb65ba6ea04d Mon Sep 17 00:00:00 2001 +From 25d2b378d13a6472ff7fe16dd98289b75cac352e Mon Sep 17 00:00:00 2001 From: Anton Fedchin <afedchin@ruswizards.com> Date: Tue, 23 Feb 2016 16:02:46 +0300 -Subject: [PATCH 45/67] [3DBD] Added support of 3D-BluRay playback. +Subject: [PATCH 43/61] [3DBD] Added support of 3D-BluRay playback. --- lib/DllLibbluray.h | 8 + @@ -53071,10 +48583,10 @@ index f5a337fe19beff472557c97ff7a203ad30a912b2..03f93391265e164837c2a17a8fe6d7da public: diff --git a/project/VS2010Express/XBMC.vcxproj b/project/VS2010Express/XBMC.vcxproj -index 601c5848ab9bda32e90fced986cf61dad38800bf..189b698f57d1e2bbb50dd7541136309c59a1fb84 100644 +index 1b5c0643fe18f61df6829a4eb33c9a82fd8468a4..fdb0abb808fed44ec3d7896289defe94ee9d52b1 100644 --- a/project/VS2010Express/XBMC.vcxproj +++ b/project/VS2010Express/XBMC.vcxproj -@@ -295,6 +295,7 @@ copy "..\Win32BuildSetup\dependencies\python27.dll" "$(TargetDir)"</Command> +@@ -296,6 +296,7 @@ copy "..\Win32BuildSetup\dependencies\python27.dll" "$(TargetDir)"</Command> <ClCompile Include="..\..\xbmc\cores\VideoPlayer\DVDDemuxers\DVDDemuxCDDA.cpp" /> <ClCompile Include="..\..\xbmc\cores\VideoPlayer\DVDDemuxers\DVDDemuxClient.cpp" /> <ClCompile Include="..\..\xbmc\cores\VideoPlayer\DVDDemuxers\DemuxMultiSource.cpp" /> @@ -53082,7 +48594,7 @@ index 601c5848ab9bda32e90fced986cf61dad38800bf..189b698f57d1e2bbb50dd7541136309c <ClCompile Include="..\..\xbmc\cores\VideoPlayer\DVDDemuxers\DVDDemuxStreamSSIF.cpp" /> <ClCompile Include="..\..\xbmc\cores\VideoPlayer\DVDInputStreams\DVDInputStreamBluray.cpp" /> <ClCompile Include="..\..\xbmc\cores\VideoPlayer\DVDInputStreams\InputStreamMultiSource.cpp" /> -@@ -1070,6 +1071,7 @@ copy "..\Win32BuildSetup\dependencies\python27.dll" "$(TargetDir)"</Command> +@@ -1073,6 +1074,7 @@ copy "..\Win32BuildSetup\dependencies\python27.dll" "$(TargetDir)"</Command> <ClInclude Include="..\..\xbmc\cores\VideoPlayer\DVDDemuxers\DemuxMultiSource.h" /> <ClInclude Include="..\..\xbmc\cores\VideoPlayer\DVDDemuxers\DVDDemuxPacket.h" /> <ClInclude Include="..\..\xbmc\cores\VideoPlayer\Process\ProcessInfo.h" /> @@ -53091,10 +48603,10 @@ index 601c5848ab9bda32e90fced986cf61dad38800bf..189b698f57d1e2bbb50dd7541136309c <ClInclude Include="..\..\xbmc\cores\VideoPlayer\VideoRenderers\BaseRenderer.h" /> <ClInclude Include="..\..\xbmc\cores\VideoPlayer\VideoRenderers\DebugRenderer.h" /> diff --git a/project/VS2010Express/XBMC.vcxproj.filters b/project/VS2010Express/XBMC.vcxproj.filters -index b2d5230fdcd32f6db50e580f55cd7a63d4d19247..65d8e075716c05669c1e5665de9e3ba0ac1188ea 100644 +index 0524f95c8549be034a3592b2c1909d688f0c9b17..049aa3e93113bbaaa144dc9292be7832e8f5f696 100644 --- a/project/VS2010Express/XBMC.vcxproj.filters +++ b/project/VS2010Express/XBMC.vcxproj.filters -@@ -3455,6 +3455,9 @@ +@@ -3458,6 +3458,9 @@ <ClCompile Include="..\..\xbmc\cores\VideoPlayer\DVDDemuxers\DVDDemuxStreamSSIF.cpp"> <Filter>cores\VideoPlayer\DVDDemuxers</Filter> </ClCompile> @@ -53103,8 +48615,8 @@ index b2d5230fdcd32f6db50e580f55cd7a63d4d19247..65d8e075716c05669c1e5665de9e3ba0 + </ClCompile> </ItemGroup> <ItemGroup> - <ClInclude Include="..\..\xbmc\win32\pch.h"> -@@ -6710,6 +6713,9 @@ + <ClInclude Include="..\..\xbmc\platform\win32\pch.h"> +@@ -6728,6 +6731,9 @@ <ClInclude Include="..\..\xbmc\cores\VideoPlayer\DVDDemuxers\DVDDemuxStreamSSIF.h"> <Filter>cores\VideoPlayer\DVDDemuxers</Filter> </ClInclude> @@ -53113,9 +48625,9 @@ index b2d5230fdcd32f6db50e580f55cd7a63d4d19247..65d8e075716c05669c1e5665de9e3ba0 + </ClInclude> </ItemGroup> <ItemGroup> - <ResourceCompile Include="..\..\xbmc\win32\XBMC_PC.rc"> + <ResourceCompile Include="..\..\xbmc\platform\win32\XBMC_PC.rc"> diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/CMakeLists.txt b/xbmc/cores/VideoPlayer/DVDDemuxers/CMakeLists.txt -index 65b369054c4ea329649a51f20f448394c70b110d..2706bcadc177a4f8f9c12c3be7976f7a0f81fc8f 100644 +index 0da129ff99f57dc38ca8a854854d9fe658651e1f..82d4b499245afda1a51ca281584cc47fc76173d1 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/CMakeLists.txt +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/CMakeLists.txt @@ -5,6 +5,7 @@ set(SOURCES DemuxMultiSource.cpp @@ -53135,7 +48647,7 @@ index 65b369054c4ea329649a51f20f448394c70b110d..2706bcadc177a4f8f9c12c3be7976f7a DVDDemuxPacket.h DVDDemuxUtils.h diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -index 4490b16318e1c54822cdbbf5fa6344d66c2fdbdd..54e4d0b66680a08c1e4c1be343fabe4371aec6af 100644 +index 5775a82c37768bc585645ff5a8eb259c07ef9f9c..65d998f65493c1b463a4d1cabf36a16c9a06d498 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp @@ -27,6 +27,7 @@ @@ -53196,7 +48708,7 @@ index 4490b16318e1c54822cdbbf5fa6344d66c2fdbdd..54e4d0b66680a08c1e4c1be343fabe43 if (stream->type == STREAM_DATA && stream->codec == AV_CODEC_ID_H264_MVC && pPacket->iSize) stream = GetStream(pPacket->iStreamId); } -@@ -1375,6 +1380,29 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) +@@ -1388,6 +1393,29 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) { m_pSSIF->SetH264StreamId(streamIdx); pStream->codec->codec_tag = MKTAG('A', 'M', 'V', 'C'); @@ -53226,7 +48738,7 @@ index 4490b16318e1c54822cdbbf5fa6344d66c2fdbdd..54e4d0b66680a08c1e4c1be343fabe43 } } else if (CDVDCodecUtils::ProcessH264MVCExtradata(pStream->codec->extradata, pStream->codec->extradata_size)) -@@ -1635,6 +1663,12 @@ bool CDVDDemuxFFmpeg::SeekChapter(int chapter, double* startpts) +@@ -1648,6 +1676,12 @@ bool CDVDDemuxFFmpeg::SeekChapter(int chapter, double* startpts) } Flush(); @@ -53239,7 +48751,7 @@ index 4490b16318e1c54822cdbbf5fa6344d66c2fdbdd..54e4d0b66680a08c1e4c1be343fabe43 return true; } -@@ -1704,6 +1738,11 @@ std::string CDVDDemuxFFmpeg::GetStreamCodecName(int iStreamId) +@@ -1717,6 +1751,11 @@ std::string CDVDDemuxFFmpeg::GetStreamCodecName(int iStreamId) bool CDVDDemuxFFmpeg::IsProgramChange() { @@ -54056,10 +49568,10 @@ index b967a85e6557e42a7f1235cdd804d5a0263b866f..561fb5cd4f971bc9ee4f41218a60bb3d typedef std::shared_ptr<CDVDOverlayImage> SOverlay; typedef std::list<SOverlay> SOverlays; -From 9209fd1862041094e9f01e17c377c6d50c37ebb0 Mon Sep 17 00:00:00 2001 +From fab0e4608dd6560b9c001eb1189cd000e90439f9 Mon Sep 17 00:00:00 2001 From: Anton Fedchin <afedchin@ruswizards.com> Date: Wed, 2 Mar 2016 23:31:50 +0300 -Subject: [PATCH 46/67] [BaseRenderer] Fix aspect for TAB/SBS (need more +Subject: [PATCH 44/61] [BaseRenderer] Fix aspect for TAB/SBS (need more testing) --- @@ -54103,94 +49615,41 @@ index f18c671d90c85eed1ca4bd52028d7e5074a1312a..5c6f7453c2b3fd1155c18af8d37cb3d4 void CBaseRenderer::ManageRenderArea() -From 7aa4746fe6adef77e5ff99b60d242a575fff583c Mon Sep 17 00:00:00 2001 +From 4e661a9b6bafbcfcafdcc33acdbebaa778c947f7 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Mon, 29 Feb 2016 17:00:50 +0000 -Subject: [PATCH 47/67] libbluray: Bump to Nevcairie's v0.9.2 +Subject: [PATCH 45/61] libbluray: Bump to Nevcairie's v0.9.2 This includes 3D support --- - tools/depends/target/libbluray/Makefile | 1 + - .../libbluray/bump_to_Nevcairie_v0.9.2.patch | 24397 +++++++++++++++++++ - 2 files changed, 24398 insertions(+) + tools/depends/target/libbluray/Makefile | 1 + + .../libbluray/bump_to_Nevcairie_v0.9.2.patch | 1629 ++++++++++++++++++++ + 2 files changed, 1630 insertions(+) create mode 100644 tools/depends/target/libbluray/bump_to_Nevcairie_v0.9.2.patch diff --git a/tools/depends/target/libbluray/Makefile b/tools/depends/target/libbluray/Makefile -index 3c85b96ca38409fec6de87cb30162b725ce170db..d8fa16ed83ea997c8b3cf34ee83383e830986197 100644 +index 09d2a8e04ef4ef694f3d7a6152ab9be0e294ce2f..741a820df47fd8014192f6c0c546abb72d33ab1f 100644 --- a/tools/depends/target/libbluray/Makefile +++ b/tools/depends/target/libbluray/Makefile -@@ -27,6 +27,7 @@ $(PLATFORM): $(TARBALLS_LOCATION)/$(ARCHIVE) $(DEPS) - ifeq ($(OS),android) - cd $(PLATFORM); patch -p1 < ../android.patch - endif +@@ -24,6 +24,7 @@ $(PLATFORM): $(TARBALLS_LOCATION)/$(ARCHIVE) $(DEPS) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + # libbluray has borked Makefile.am with respect to CFLAGS, remove the offending line + sed -i -e "s|CFLAGS=|#CFLAGS=|" $(PLATFORM)/Makefile.am + cd $(PLATFORM); patch -p1 < ../bump_to_Nevcairie_v0.9.2.patch cd $(PLATFORM); ./bootstrap cd $(PLATFORM); $(CONFIGURE) diff --git a/tools/depends/target/libbluray/bump_to_Nevcairie_v0.9.2.patch b/tools/depends/target/libbluray/bump_to_Nevcairie_v0.9.2.patch new file mode 100644 -index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed41072c65354a +index 0000000000000000000000000000000000000000..5ef0124e35c9d81143921a328e272220640fb84e --- /dev/null +++ b/tools/depends/target/libbluray/bump_to_Nevcairie_v0.9.2.patch -@@ -0,0 +1,24397 @@ -+diff --git a/ChangeLog b/ChangeLog -+index ffc7788..545fb3f 100644 -+--- a/ChangeLog -++++ b/ChangeLog -+@@ -1,3 +1,29 @@ -++2015-12-01: Version 0.9.2 -++- Add primary audio stream to bd_select_stream(). -++- Improve error resilience. -++- Fix Java 8 compability issues. -++- Fix Android build. -++- Fix SecurityException in AWTAutoShutdown. -++- Fix BD-J check when install path in Windows contains non-ASCII chars. -++- Fix jvm.dll loading in Windows ($JAVA_HOME/bin should be in dll load path). -++- Fix class translating in recent Java 8 versions. -++ -++2015-11-03: Version 0.9.1 -++- Improved BD-J security. -++- Improved error resilience. -++- Improved seeking (avoid skipping PAT/PMT/PCR). -++- Fix UO mask check when bd_play_title() is used for Top Menu. -++- Fix re-starting of title bound Xlets when title changes. -++- Fix loading classes with invalid debug info. -++ -++2015-10-02: Version 0.9.0 -++- Add functions to read files from VFS. -++- Improved error resilience. -++- Improved BD-J compability. -++- Fix Xlet-initiated font caching. -++- Fix return value when setting BLURAY_PLAYER_SETTING_DECODE_PG. -++- Fix build with C++ compiler -++ -+ 2015-05-15: Version 0.8.1 -+ - Notify application when UO mask changes. -+ - Improved error resilience. +@@ -0,0 +1,1629 @@ +diff --git a/Makefile.am b/Makefile.am -+index e03e926..87093c4 100644 ++index 3a54bfc..035553b 100644 +--- a/Makefile.am ++++ b/Makefile.am -+@@ -26,7 +26,8 @@ EXTRA_DIST = \ -+ src/libbluray/bdj/build.xml \ -+ src/libbluray/bdj/java \ -+ src/libbluray/bdj/java-j2me \ -+- src/libbluray/bdj/java-j2se -++ src/libbluray/bdj/java-j2se \ -++ contrib/asm -+ -+ lib_LTLIBRARIES=libbluray.la -+ libbluray_la_SOURCES = \ -+@@ -149,7 +150,7 @@ libbluray_la_SOURCES+= \ -+ endif -+ endif -+ -+-libbluray_la_LDFLAGS= -version-info $(LT_VERSION_INFO) -export-symbols-regex "^bd_" -++libbluray_la_LDFLAGS= -no-undefined -version-info $(LT_VERSION_INFO) -export-symbols-regex "^bd_" -+ libbluray_la_LIBADD= $(LIBXML2_LIBS) $(FT2_LIBS) $(FONTCONFIG_LIBS) -+ -+ noinst_HEADERS = \ -+@@ -158,6 +159,15 @@ noinst_HEADERS = \ ++@@ -161,6 +161,15 @@ noinst_HEADERS = \ + jni/win32/jni_md.h \ + jni/darwin/jni_md.h + @@ -54206,7 +49665,7 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + pkginclude_HEADERS = \ + src/file/filesystem.h \ + src/libbluray/bluray.h \ -+@@ -165,6 +175,9 @@ pkginclude_HEADERS = \ ++@@ -168,6 +177,9 @@ pkginclude_HEADERS = \ + src/libbluray/keys.h \ + src/libbluray/player_settings.h \ + src/libbluray/bdnav/clpi_data.h \ @@ -54216,94 +49675,6 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + src/libbluray/bdnav/meta_data.h \ + src/libbluray/decoders/overlay.h \ + src/util/log_control.h -+@@ -185,10 +198,12 @@ endif -+ -+ -+ if USING_BDJAVA -++if USING_BDJAVA_BUILD_JAR -+ jardir=$(datadir)/java/ -+ jar_DATA=$(top_builddir)/.libs/libbluray-$(BDJ_TYPE)-$(VERSION).jar -+ -+ $(top_builddir)/.libs/libbluray-$(BDJ_TYPE)-$(VERSION).jar: all-local -++endif -+ -+ libbluray_la_SOURCES += \ -+ src/libbluray/bdj/bdj.h \ -+@@ -213,6 +228,7 @@ libbluray_la_SOURCES += \ -+ -+ AM_CFLAGS += $(BDJAVA_CFLAGS) -+ -++if USING_BDJAVA_BUILD_JAR -+ all-local: -+ ant -f $(top_srcdir)/src/libbluray/bdj/build.xml \ -+ -Dbuild='$(abs_builddir)/src/libbluray/bdj/build' \ -+@@ -228,6 +244,7 @@ clean-local: -+ -Dversion='$(BDJ_TYPE)-$(VERSION)' \ -+ clean -+ endif -++endif -+ -+ pkgconfigdir = $(libdir)/pkgconfig -+ pkgconfig_DATA = src/libbluray.pc -+@@ -265,20 +282,20 @@ bd_info_LDADD = libbluray.la -+ bdsplice_SOURCES = src/examples/bdsplice.c -+ bdsplice_LDADD = libbluray.la -+ -+-bdj_test_SOURCES = src/examples/bdj_test.c -++bdj_test_SOURCES = src/devtools/bdj_test.c -+ bdj_test_LDADD = libbluray.la -+ -+-bdjo_dump_SOURCES = src/examples/bdjo_dump.c -++bdjo_dump_SOURCES = src/devtools/bdjo_dump.c -+ bdjo_dump_LDADD = libbluray.la -+ -+ clpi_dump_CFLAGS = $(AM_CFLAGS) -+ clpi_dump_SOURCES = \ -+- src/examples/clpi_dump.c \ -+- src/examples/util.c \ -+- src/examples/util.h -++ src/devtools/clpi_dump.c \ -++ src/devtools/util.c \ -++ src/devtools/util.h -+ clpi_dump_LDADD = libbluray.la -+ -+-hdmv_test_SOURCES = src/examples/hdmv_test.c -++hdmv_test_SOURCES = src/devtools/hdmv_test.c -+ hdmv_test_LDADD = libbluray.la -+ -+ index_dump_SOURCES = src/examples/index_dump.c -+@@ -291,15 +308,15 @@ list_titles_SOURCES = src/examples/list_titles.c -+ list_titles_LDADD = libbluray.la -+ -+ mobj_dump_CFLAGS = $(AM_CFLAGS) -+-mobj_dump_SOURCES = src/examples/mobj_dump.c \ -++mobj_dump_SOURCES = src/devtools/mobj_dump.c \ -+ src/libbluray/hdmv/mobj_print.c -+ mobj_dump_LDADD = libbluray.la -+ -+ mpls_dump_CFLAGS = $(AM_CFLAGS) -+ mpls_dump_SOURCES = \ -+- src/examples/mpls_dump.c \ -+- src/examples/util.c \ -+- src/examples/util.h -++ src/devtools/mpls_dump.c \ -++ src/devtools/util.c \ -++ src/devtools/util.h -+ mpls_dump_LDADD = libbluray.la -+ -+ sound_dump_SOURCES = src/examples/sound_dump.c -+diff --git a/bootstrap b/bootstrap -+index 872167c..bde67cb 100755 -+--- a/bootstrap -++++ b/bootstrap -+@@ -1,3 +1,7 @@ -+ #!/bin/sh -+ -++set -e -++ -++cd "$(dirname "$0")" -++ -+ autoreconf -vif +diff --git a/config.h b/config.h +new file mode 100644 +index 0000000..6764704 @@ -54467,15024 +49838,6 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 ++ ++/* Define to '0x0502' for Windows XP SP2 APIs. */ ++#define _WIN32_WINNT 0x0502 -+diff --git a/configure.ac b/configure.ac -+index 5d5fe2c..ed08c96 100644 -+--- a/configure.ac -++++ b/configure.ac -+@@ -1,7 +1,7 @@ -+ dnl library version number -+ m4_define([bluray_major], 0) -+-m4_define([bluray_minor], 8) -+-m4_define([bluray_micro], 1) -++m4_define([bluray_minor], 9) -++m4_define([bluray_micro], 2) -+ m4_define([bluray_version],[bluray_major.bluray_minor.bluray_micro]) -+ -+ dnl shared library version (.so version) -+@@ -12,9 +12,9 @@ dnl - If interfaces have been changed or removed, increase current and set age a -+ dnl -+ dnl Library file name will be libbluray.so.(current-age).age.revision -+ dnl -+-m4_define([lt_current], 9) -+-m4_define([lt_revision], 1) -+-m4_define([lt_age], 8) -++m4_define([lt_current], 10) -++m4_define([lt_revision], 2) -++m4_define([lt_age], 9) -+ -+ dnl initilization -+ AC_INIT([libbluray], bluray_version, [http://www.videolan.org/developers/libbluray.html]) -+@@ -87,7 +87,15 @@ AC_ARG_ENABLE([bdjava], -+ [use_bdjava=yes]) -+ -+ AC_ARG_ENABLE([udf], -+- [AS_HELP_STRING([--enable-udf], [enable UDF support @<:@default=disabled@:>@])]) -++ [AS_HELP_STRING([--disable-udf], [disable UDF support @<:@default=enabled@:>@])], -++ [enable_udf=$enableval], -++ [enable_udf=yes]) -++ -++AC_ARG_ENABLE([bdjava-jar], -++ [AS_HELP_STRING([--disable-bdjava-jar], -++ [disable building of BD-Java JAR file @<:@default=enabled@:>@])], -++ [use_bdjava_jar=$enableval], -++ [use_bdjava_jar=yes]) -+ -+ AC_ARG_WITH([libxml2], -+ [AS_HELP_STRING([--without-libxml2], [build without libxml2 support @<:@default=with@:>@])]) -+@@ -224,7 +232,7 @@ if [[ $use_bdjava = "yes" ]]; then -+ ]) -+ -+ AC_CHECK_PROG(HAVE_ANT, [ant], yes, no) -+- if test "x$HAVE_ANT" = "xno"; then -++ if test "x$use_bdjava_jar" = "xyes" && test "x$HAVE_ANT" = "xno"; then -+ AC_MSG_ERROR([BD-J requires ANT, but ant was not found. Please install it.]) -+ fi -+ -+@@ -233,6 +241,7 @@ if [[ $use_bdjava = "yes" ]]; then -+ AC_DEFINE_UNQUOTED([JDK_HOME], ["$JDK_HOME"], [""]) -+ fi -+ AM_CONDITIONAL([USING_BDJAVA], [ test $use_bdjava = "yes" ]) -++AM_CONDITIONAL([USING_BDJAVA_BUILD_JAR], [ test $use_bdjava_jar = "yes" ]) -+ -+ dnl BD-J type -+ if test "$BDJ_TYPE" = "j2me"; then -+@@ -292,6 +301,7 @@ echo " --------" -+ echo " BD-J support: $use_bdjava" -+ if [[ $use_bdjava = "yes" ]]; then -+ echo " BD-J type: $BDJ_TYPE" -++echo " build JAR: $use_bdjava_jar" -+ if test x"$BDJ_BOOTCLASSPATH" != x""; then -+ echo " BD-J bootclasspath: $BDJ_BOOTCLASSPATH" -+ fi -+diff --git a/contrib/asm/LICENSE.txt b/contrib/asm/LICENSE.txt -+new file mode 100644 -+index 0000000..4d19185 -+--- /dev/null -++++ b/contrib/asm/LICENSE.txt -+@@ -0,0 +1,28 @@ -++ -++ ASM: a very small and fast Java bytecode manipulation framework -++ Copyright (c) 2000-2011 INRIA, France Telecom -++ All rights reserved. -++ -++ Redistribution and use in source and binary forms, with or without -++ modification, are permitted provided that the following conditions -++ are met: -++ 1. Redistributions of source code must retain the above copyright -++ notice, this list of conditions and the following disclaimer. -++ 2. Redistributions in binary form must reproduce the above copyright -++ notice, this list of conditions and the following disclaimer in the -++ documentation and/or other materials provided with the distribution. -++ 3. Neither the name of the copyright holders nor the names of its -++ contributors may be used to endorse or promote products derived from -++ this software without specific prior written permission. -++ -++ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ THE POSSIBILITY OF SUCH DAMAGE. -+diff --git a/contrib/asm/SOURCE b/contrib/asm/SOURCE -+new file mode 100644 -+index 0000000..804aede -+--- /dev/null -++++ b/contrib/asm/SOURCE -+@@ -0,0 +1,9 @@ -++Core functionality from asm 5.0.4 -++ -++http://asm.ow2.org/ -++ -++ASM is an all purpose Java bytecode manipulation and analysis framework. It can be used to modify -++existing classes or dynamically generate classes, directly in binary form. Provided common -++transformations and analysis algorithms allow to easily assemble custom complex transformations -++and code analysis tools. -++ -+diff --git a/contrib/asm/src/org/objectweb/asm/AnnotationVisitor.java b/contrib/asm/src/org/objectweb/asm/AnnotationVisitor.java -+new file mode 100644 -+index 0000000..b644083 -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/AnnotationVisitor.java -+@@ -0,0 +1,169 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * A visitor to visit a Java annotation. The methods of this class must be -++ * called in the following order: ( <tt>visit</tt> | <tt>visitEnum</tt> | -++ * <tt>visitAnnotation</tt> | <tt>visitArray</tt> )* <tt>visitEnd</tt>. -++ * -++ * @author Eric Bruneton -++ * @author Eugene Kuleshov -++ */ -++public abstract class AnnotationVisitor { -++ -++ /** -++ * The ASM API version implemented by this visitor. The value of this field -++ * must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -++ */ -++ protected final int api; -++ -++ /** -++ * The annotation visitor to which this visitor must delegate method calls. -++ * May be null. -++ */ -++ protected AnnotationVisitor av; -++ -++ /** -++ * Constructs a new {@link AnnotationVisitor}. -++ * -++ * @param api -++ * the ASM API version implemented by this visitor. Must be one -++ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -++ */ -++ public AnnotationVisitor(final int api) { -++ this(api, null); -++ } -++ -++ /** -++ * Constructs a new {@link AnnotationVisitor}. -++ * -++ * @param api -++ * the ASM API version implemented by this visitor. Must be one -++ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -++ * @param av -++ * the annotation visitor to which this visitor must delegate -++ * method calls. May be null. -++ */ -++ public AnnotationVisitor(final int api, final AnnotationVisitor av) { -++ if (api != Opcodes.ASM4 && api != Opcodes.ASM5) { -++ throw new IllegalArgumentException(); -++ } -++ this.api = api; -++ this.av = av; -++ } -++ -++ /** -++ * Visits a primitive value of the annotation. -++ * -++ * @param name -++ * the value name. -++ * @param value -++ * the actual value, whose type must be {@link Byte}, -++ * {@link Boolean}, {@link Character}, {@link Short}, -++ * {@link Integer} , {@link Long}, {@link Float}, {@link Double}, -++ * {@link String} or {@link Type} or OBJECT or ARRAY sort. This -++ * value can also be an array of byte, boolean, short, char, int, -++ * long, float or double values (this is equivalent to using -++ * {@link #visitArray visitArray} and visiting each array element -++ * in turn, but is more convenient). -++ */ -++ public void visit(String name, Object value) { -++ if (av != null) { -++ av.visit(name, value); -++ } -++ } -++ -++ /** -++ * Visits an enumeration value of the annotation. -++ * -++ * @param name -++ * the value name. -++ * @param desc -++ * the class descriptor of the enumeration class. -++ * @param value -++ * the actual enumeration value. -++ */ -++ public void visitEnum(String name, String desc, String value) { -++ if (av != null) { -++ av.visitEnum(name, desc, value); -++ } -++ } -++ -++ /** -++ * Visits a nested annotation value of the annotation. -++ * -++ * @param name -++ * the value name. -++ * @param desc -++ * the class descriptor of the nested annotation class. -++ * @return a visitor to visit the actual nested annotation value, or -++ * <tt>null</tt> if this visitor is not interested in visiting this -++ * nested annotation. <i>The nested annotation value must be fully -++ * visited before calling other methods on this annotation -++ * visitor</i>. -++ */ -++ public AnnotationVisitor visitAnnotation(String name, String desc) { -++ if (av != null) { -++ return av.visitAnnotation(name, desc); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits an array value of the annotation. Note that arrays of primitive -++ * types (such as byte, boolean, short, char, int, long, float or double) -++ * can be passed as value to {@link #visit visit}. This is what -++ * {@link ClassReader} does. -++ * -++ * @param name -++ * the value name. -++ * @return a visitor to visit the actual array value elements, or -++ * <tt>null</tt> if this visitor is not interested in visiting these -++ * values. The 'name' parameters passed to the methods of this -++ * visitor are ignored. <i>All the array values must be visited -++ * before calling other methods on this annotation visitor</i>. -++ */ -++ public AnnotationVisitor visitArray(String name) { -++ if (av != null) { -++ return av.visitArray(name); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits the end of the annotation. -++ */ -++ public void visitEnd() { -++ if (av != null) { -++ av.visitEnd(); -++ } -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/AnnotationWriter.java b/contrib/asm/src/org/objectweb/asm/AnnotationWriter.java -+new file mode 100644 -+index 0000000..6b95608 -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/AnnotationWriter.java -+@@ -0,0 +1,371 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * An {@link AnnotationVisitor} that generates annotations in bytecode form. -++ * -++ * @author Eric Bruneton -++ * @author Eugene Kuleshov -++ */ -++final class AnnotationWriter extends AnnotationVisitor { -++ -++ /** -++ * The class writer to which this annotation must be added. -++ */ -++ private final ClassWriter cw; -++ -++ /** -++ * The number of values in this annotation. -++ */ -++ private int size; -++ -++ /** -++ * <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation -++ * writers used for annotation default and annotation arrays use unnamed -++ * values. -++ */ -++ private final boolean named; -++ -++ /** -++ * The annotation values in bytecode form. This byte vector only contains -++ * the values themselves, i.e. the number of values must be stored as a -++ * unsigned short just before these bytes. -++ */ -++ private final ByteVector bv; -++ -++ /** -++ * The byte vector to be used to store the number of values of this -++ * annotation. See {@link #bv}. -++ */ -++ private final ByteVector parent; -++ -++ /** -++ * Where the number of values of this annotation must be stored in -++ * {@link #parent}. -++ */ -++ private final int offset; -++ -++ /** -++ * Next annotation writer. This field is used to store annotation lists. -++ */ -++ AnnotationWriter next; -++ -++ /** -++ * Previous annotation writer. This field is used to store annotation lists. -++ */ -++ AnnotationWriter prev; -++ -++ // ------------------------------------------------------------------------ -++ // Constructor -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Constructs a new {@link AnnotationWriter}. -++ * -++ * @param cw -++ * the class writer to which this annotation must be added. -++ * @param named -++ * <tt>true<tt> if values are named, <tt>false</tt> otherwise. -++ * @param bv -++ * where the annotation values must be stored. -++ * @param parent -++ * where the number of annotation values must be stored. -++ * @param offset -++ * where in <tt>parent</tt> the number of annotation values must -++ * be stored. -++ */ -++ AnnotationWriter(final ClassWriter cw, final boolean named, -++ final ByteVector bv, final ByteVector parent, final int offset) { -++ super(Opcodes.ASM5); -++ this.cw = cw; -++ this.named = named; -++ this.bv = bv; -++ this.parent = parent; -++ this.offset = offset; -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Implementation of the AnnotationVisitor abstract class -++ // ------------------------------------------------------------------------ -++ -++ @Override -++ public void visit(final String name, final Object value) { -++ ++size; -++ if (named) { -++ bv.putShort(cw.newUTF8(name)); -++ } -++ if (value instanceof String) { -++ bv.put12('s', cw.newUTF8((String) value)); -++ } else if (value instanceof Byte) { -++ bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index); -++ } else if (value instanceof Boolean) { -++ int v = ((Boolean) value).booleanValue() ? 1 : 0; -++ bv.put12('Z', cw.newInteger(v).index); -++ } else if (value instanceof Character) { -++ bv.put12('C', cw.newInteger(((Character) value).charValue()).index); -++ } else if (value instanceof Short) { -++ bv.put12('S', cw.newInteger(((Short) value).shortValue()).index); -++ } else if (value instanceof Type) { -++ bv.put12('c', cw.newUTF8(((Type) value).getDescriptor())); -++ } else if (value instanceof byte[]) { -++ byte[] v = (byte[]) value; -++ bv.put12('[', v.length); -++ for (int i = 0; i < v.length; i++) { -++ bv.put12('B', cw.newInteger(v[i]).index); -++ } -++ } else if (value instanceof boolean[]) { -++ boolean[] v = (boolean[]) value; -++ bv.put12('[', v.length); -++ for (int i = 0; i < v.length; i++) { -++ bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index); -++ } -++ } else if (value instanceof short[]) { -++ short[] v = (short[]) value; -++ bv.put12('[', v.length); -++ for (int i = 0; i < v.length; i++) { -++ bv.put12('S', cw.newInteger(v[i]).index); -++ } -++ } else if (value instanceof char[]) { -++ char[] v = (char[]) value; -++ bv.put12('[', v.length); -++ for (int i = 0; i < v.length; i++) { -++ bv.put12('C', cw.newInteger(v[i]).index); -++ } -++ } else if (value instanceof int[]) { -++ int[] v = (int[]) value; -++ bv.put12('[', v.length); -++ for (int i = 0; i < v.length; i++) { -++ bv.put12('I', cw.newInteger(v[i]).index); -++ } -++ } else if (value instanceof long[]) { -++ long[] v = (long[]) value; -++ bv.put12('[', v.length); -++ for (int i = 0; i < v.length; i++) { -++ bv.put12('J', cw.newLong(v[i]).index); -++ } -++ } else if (value instanceof float[]) { -++ float[] v = (float[]) value; -++ bv.put12('[', v.length); -++ for (int i = 0; i < v.length; i++) { -++ bv.put12('F', cw.newFloat(v[i]).index); -++ } -++ } else if (value instanceof double[]) { -++ double[] v = (double[]) value; -++ bv.put12('[', v.length); -++ for (int i = 0; i < v.length; i++) { -++ bv.put12('D', cw.newDouble(v[i]).index); -++ } -++ } else { -++ Item i = cw.newConstItem(value); -++ bv.put12(".s.IFJDCS".charAt(i.type), i.index); -++ } -++ } -++ -++ @Override -++ public void visitEnum(final String name, final String desc, -++ final String value) { -++ ++size; -++ if (named) { -++ bv.putShort(cw.newUTF8(name)); -++ } -++ bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value)); -++ } -++ -++ @Override -++ public AnnotationVisitor visitAnnotation(final String name, -++ final String desc) { -++ ++size; -++ if (named) { -++ bv.putShort(cw.newUTF8(name)); -++ } -++ // write tag and type, and reserve space for values count -++ bv.put12('@', cw.newUTF8(desc)).putShort(0); -++ return new AnnotationWriter(cw, true, bv, bv, bv.length - 2); -++ } -++ -++ @Override -++ public AnnotationVisitor visitArray(final String name) { -++ ++size; -++ if (named) { -++ bv.putShort(cw.newUTF8(name)); -++ } -++ // write tag, and reserve space for array size -++ bv.put12('[', 0); -++ return new AnnotationWriter(cw, false, bv, bv, bv.length - 2); -++ } -++ -++ @Override -++ public void visitEnd() { -++ if (parent != null) { -++ byte[] data = parent.data; -++ data[offset] = (byte) (size >>> 8); -++ data[offset + 1] = (byte) size; -++ } -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Utility methods -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Returns the size of this annotation writer list. -++ * -++ * @return the size of this annotation writer list. -++ */ -++ int getSize() { -++ int size = 0; -++ AnnotationWriter aw = this; -++ while (aw != null) { -++ size += aw.bv.length; -++ aw = aw.next; -++ } -++ return size; -++ } -++ -++ /** -++ * Puts the annotations of this annotation writer list into the given byte -++ * vector. -++ * -++ * @param out -++ * where the annotations must be put. -++ */ -++ void put(final ByteVector out) { -++ int n = 0; -++ int size = 2; -++ AnnotationWriter aw = this; -++ AnnotationWriter last = null; -++ while (aw != null) { -++ ++n; -++ size += aw.bv.length; -++ aw.visitEnd(); // in case user forgot to call visitEnd -++ aw.prev = last; -++ last = aw; -++ aw = aw.next; -++ } -++ out.putInt(size); -++ out.putShort(n); -++ aw = last; -++ while (aw != null) { -++ out.putByteArray(aw.bv.data, 0, aw.bv.length); -++ aw = aw.prev; -++ } -++ } -++ -++ /** -++ * Puts the given annotation lists into the given byte vector. -++ * -++ * @param panns -++ * an array of annotation writer lists. -++ * @param off -++ * index of the first annotation to be written. -++ * @param out -++ * where the annotations must be put. -++ */ -++ static void put(final AnnotationWriter[] panns, final int off, -++ final ByteVector out) { -++ int size = 1 + 2 * (panns.length - off); -++ for (int i = off; i < panns.length; ++i) { -++ size += panns[i] == null ? 0 : panns[i].getSize(); -++ } -++ out.putInt(size).putByte(panns.length - off); -++ for (int i = off; i < panns.length; ++i) { -++ AnnotationWriter aw = panns[i]; -++ AnnotationWriter last = null; -++ int n = 0; -++ while (aw != null) { -++ ++n; -++ aw.visitEnd(); // in case user forgot to call visitEnd -++ aw.prev = last; -++ last = aw; -++ aw = aw.next; -++ } -++ out.putShort(n); -++ aw = last; -++ while (aw != null) { -++ out.putByteArray(aw.bv.data, 0, aw.bv.length); -++ aw = aw.prev; -++ } -++ } -++ } -++ -++ /** -++ * Puts the given type reference and type path into the given bytevector. -++ * LOCAL_VARIABLE and RESOURCE_VARIABLE target types are not supported. -++ * -++ * @param typeRef -++ * a reference to the annotated type. See {@link TypeReference}. -++ * @param typePath -++ * the path to the annotated type argument, wildcard bound, array -++ * element type, or static inner type within 'typeRef'. May be -++ * <tt>null</tt> if the annotation targets 'typeRef' as a whole. -++ * @param out -++ * where the type reference and type path must be put. -++ */ -++ static void putTarget(int typeRef, TypePath typePath, ByteVector out) { -++ switch (typeRef >>> 24) { -++ case 0x00: // CLASS_TYPE_PARAMETER -++ case 0x01: // METHOD_TYPE_PARAMETER -++ case 0x16: // METHOD_FORMAL_PARAMETER -++ out.putShort(typeRef >>> 16); -++ break; -++ case 0x13: // FIELD -++ case 0x14: // METHOD_RETURN -++ case 0x15: // METHOD_RECEIVER -++ out.putByte(typeRef >>> 24); -++ break; -++ case 0x47: // CAST -++ case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT -++ case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT -++ case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT -++ case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT -++ out.putInt(typeRef); -++ break; -++ // case 0x10: // CLASS_EXTENDS -++ // case 0x11: // CLASS_TYPE_PARAMETER_BOUND -++ // case 0x12: // METHOD_TYPE_PARAMETER_BOUND -++ // case 0x17: // THROWS -++ // case 0x42: // EXCEPTION_PARAMETER -++ // case 0x43: // INSTANCEOF -++ // case 0x44: // NEW -++ // case 0x45: // CONSTRUCTOR_REFERENCE -++ // case 0x46: // METHOD_REFERENCE -++ default: -++ out.put12(typeRef >>> 24, (typeRef & 0xFFFF00) >> 8); -++ break; -++ } -++ if (typePath == null) { -++ out.putByte(0); -++ } else { -++ int length = typePath.b[typePath.offset] * 2 + 1; -++ out.putByteArray(typePath.b, typePath.offset, length); -++ } -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/Attribute.java b/contrib/asm/src/org/objectweb/asm/Attribute.java -+new file mode 100644 -+index 0000000..8a2a882 -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/Attribute.java -+@@ -0,0 +1,255 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * A non standard class, field, method or code attribute. -++ * -++ * @author Eric Bruneton -++ * @author Eugene Kuleshov -++ */ -++public class Attribute { -++ -++ /** -++ * The type of this attribute. -++ */ -++ public final String type; -++ -++ /** -++ * The raw value of this attribute, used only for unknown attributes. -++ */ -++ byte[] value; -++ -++ /** -++ * The next attribute in this attribute list. May be <tt>null</tt>. -++ */ -++ Attribute next; -++ -++ /** -++ * Constructs a new empty attribute. -++ * -++ * @param type -++ * the type of the attribute. -++ */ -++ protected Attribute(final String type) { -++ this.type = type; -++ } -++ -++ /** -++ * Returns <tt>true</tt> if this type of attribute is unknown. The default -++ * implementation of this method always returns <tt>true</tt>. -++ * -++ * @return <tt>true</tt> if this type of attribute is unknown. -++ */ -++ public boolean isUnknown() { -++ return true; -++ } -++ -++ /** -++ * Returns <tt>true</tt> if this type of attribute is a code attribute. -++ * -++ * @return <tt>true</tt> if this type of attribute is a code attribute. -++ */ -++ public boolean isCodeAttribute() { -++ return false; -++ } -++ -++ /** -++ * Returns the labels corresponding to this attribute. -++ * -++ * @return the labels corresponding to this attribute, or <tt>null</tt> if -++ * this attribute is not a code attribute that contains labels. -++ */ -++ protected Label[] getLabels() { -++ return null; -++ } -++ -++ /** -++ * Reads a {@link #type type} attribute. This method must return a -++ * <i>new</i> {@link Attribute} object, of type {@link #type type}, -++ * corresponding to the <tt>len</tt> bytes starting at the given offset, in -++ * the given class reader. -++ * -++ * @param cr -++ * the class that contains the attribute to be read. -++ * @param off -++ * index of the first byte of the attribute's content in -++ * {@link ClassReader#b cr.b}. The 6 attribute header bytes, -++ * containing the type and the length of the attribute, are not -++ * taken into account here. -++ * @param len -++ * the length of the attribute's content. -++ * @param buf -++ * buffer to be used to call {@link ClassReader#readUTF8 -++ * readUTF8}, {@link ClassReader#readClass(int,char[]) readClass} -++ * or {@link ClassReader#readConst readConst}. -++ * @param codeOff -++ * index of the first byte of code's attribute content in -++ * {@link ClassReader#b cr.b}, or -1 if the attribute to be read -++ * is not a code attribute. The 6 attribute header bytes, -++ * containing the type and the length of the attribute, are not -++ * taken into account here. -++ * @param labels -++ * the labels of the method's code, or <tt>null</tt> if the -++ * attribute to be read is not a code attribute. -++ * @return a <i>new</i> {@link Attribute} object corresponding to the given -++ * bytes. -++ */ -++ protected Attribute read(final ClassReader cr, final int off, -++ final int len, final char[] buf, final int codeOff, -++ final Label[] labels) { -++ Attribute attr = new Attribute(type); -++ attr.value = new byte[len]; -++ System.arraycopy(cr.b, off, attr.value, 0, len); -++ return attr; -++ } -++ -++ /** -++ * Returns the byte array form of this attribute. -++ * -++ * @param cw -++ * the class to which this attribute must be added. This -++ * parameter can be used to add to the constant pool of this -++ * class the items that corresponds to this attribute. -++ * @param code -++ * the bytecode of the method corresponding to this code -++ * attribute, or <tt>null</tt> if this attribute is not a code -++ * attributes. -++ * @param len -++ * the length of the bytecode of the method corresponding to this -++ * code attribute, or <tt>null</tt> if this attribute is not a -++ * code attribute. -++ * @param maxStack -++ * the maximum stack size of the method corresponding to this -++ * code attribute, or -1 if this attribute is not a code -++ * attribute. -++ * @param maxLocals -++ * the maximum number of local variables of the method -++ * corresponding to this code attribute, or -1 if this attribute -++ * is not a code attribute. -++ * @return the byte array form of this attribute. -++ */ -++ protected ByteVector write(final ClassWriter cw, final byte[] code, -++ final int len, final int maxStack, final int maxLocals) { -++ ByteVector v = new ByteVector(); -++ v.data = value; -++ v.length = value.length; -++ return v; -++ } -++ -++ /** -++ * Returns the length of the attribute list that begins with this attribute. -++ * -++ * @return the length of the attribute list that begins with this attribute. -++ */ -++ final int getCount() { -++ int count = 0; -++ Attribute attr = this; -++ while (attr != null) { -++ count += 1; -++ attr = attr.next; -++ } -++ return count; -++ } -++ -++ /** -++ * Returns the size of all the attributes in this attribute list. -++ * -++ * @param cw -++ * the class writer to be used to convert the attributes into -++ * byte arrays, with the {@link #write write} method. -++ * @param code -++ * the bytecode of the method corresponding to these code -++ * attributes, or <tt>null</tt> if these attributes are not code -++ * attributes. -++ * @param len -++ * the length of the bytecode of the method corresponding to -++ * these code attributes, or <tt>null</tt> if these attributes -++ * are not code attributes. -++ * @param maxStack -++ * the maximum stack size of the method corresponding to these -++ * code attributes, or -1 if these attributes are not code -++ * attributes. -++ * @param maxLocals -++ * the maximum number of local variables of the method -++ * corresponding to these code attributes, or -1 if these -++ * attributes are not code attributes. -++ * @return the size of all the attributes in this attribute list. This size -++ * includes the size of the attribute headers. -++ */ -++ final int getSize(final ClassWriter cw, final byte[] code, final int len, -++ final int maxStack, final int maxLocals) { -++ Attribute attr = this; -++ int size = 0; -++ while (attr != null) { -++ cw.newUTF8(attr.type); -++ size += attr.write(cw, code, len, maxStack, maxLocals).length + 6; -++ attr = attr.next; -++ } -++ return size; -++ } -++ -++ /** -++ * Writes all the attributes of this attribute list in the given byte -++ * vector. -++ * -++ * @param cw -++ * the class writer to be used to convert the attributes into -++ * byte arrays, with the {@link #write write} method. -++ * @param code -++ * the bytecode of the method corresponding to these code -++ * attributes, or <tt>null</tt> if these attributes are not code -++ * attributes. -++ * @param len -++ * the length of the bytecode of the method corresponding to -++ * these code attributes, or <tt>null</tt> if these attributes -++ * are not code attributes. -++ * @param maxStack -++ * the maximum stack size of the method corresponding to these -++ * code attributes, or -1 if these attributes are not code -++ * attributes. -++ * @param maxLocals -++ * the maximum number of local variables of the method -++ * corresponding to these code attributes, or -1 if these -++ * attributes are not code attributes. -++ * @param out -++ * where the attributes must be written. -++ */ -++ final void put(final ClassWriter cw, final byte[] code, final int len, -++ final int maxStack, final int maxLocals, final ByteVector out) { -++ Attribute attr = this; -++ while (attr != null) { -++ ByteVector b = attr.write(cw, code, len, maxStack, maxLocals); -++ out.putShort(cw.newUTF8(attr.type)).putInt(b.length); -++ out.putByteArray(b.data, 0, b.length); -++ attr = attr.next; -++ } -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/ByteVector.java b/contrib/asm/src/org/objectweb/asm/ByteVector.java -+new file mode 100644 -+index 0000000..9c532be -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/ByteVector.java -+@@ -0,0 +1,339 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * A dynamically extensible vector of bytes. This class is roughly equivalent to -++ * a DataOutputStream on top of a ByteArrayOutputStream, but is more efficient. -++ * -++ * @author Eric Bruneton -++ */ -++public class ByteVector { -++ -++ /** -++ * The content of this vector. -++ */ -++ byte[] data; -++ -++ /** -++ * Actual number of bytes in this vector. -++ */ -++ int length; -++ -++ /** -++ * Constructs a new {@link ByteVector ByteVector} with a default initial -++ * size. -++ */ -++ public ByteVector() { -++ data = new byte[64]; -++ } -++ -++ /** -++ * Constructs a new {@link ByteVector ByteVector} with the given initial -++ * size. -++ * -++ * @param initialSize -++ * the initial size of the byte vector to be constructed. -++ */ -++ public ByteVector(final int initialSize) { -++ data = new byte[initialSize]; -++ } -++ -++ /** -++ * Puts a byte into this byte vector. The byte vector is automatically -++ * enlarged if necessary. -++ * -++ * @param b -++ * a byte. -++ * @return this byte vector. -++ */ -++ public ByteVector putByte(final int b) { -++ int length = this.length; -++ if (length + 1 > data.length) { -++ enlarge(1); -++ } -++ data[length++] = (byte) b; -++ this.length = length; -++ return this; -++ } -++ -++ /** -++ * Puts two bytes into this byte vector. The byte vector is automatically -++ * enlarged if necessary. -++ * -++ * @param b1 -++ * a byte. -++ * @param b2 -++ * another byte. -++ * @return this byte vector. -++ */ -++ ByteVector put11(final int b1, final int b2) { -++ int length = this.length; -++ if (length + 2 > data.length) { -++ enlarge(2); -++ } -++ byte[] data = this.data; -++ data[length++] = (byte) b1; -++ data[length++] = (byte) b2; -++ this.length = length; -++ return this; -++ } -++ -++ /** -++ * Puts a short into this byte vector. The byte vector is automatically -++ * enlarged if necessary. -++ * -++ * @param s -++ * a short. -++ * @return this byte vector. -++ */ -++ public ByteVector putShort(final int s) { -++ int length = this.length; -++ if (length + 2 > data.length) { -++ enlarge(2); -++ } -++ byte[] data = this.data; -++ data[length++] = (byte) (s >>> 8); -++ data[length++] = (byte) s; -++ this.length = length; -++ return this; -++ } -++ -++ /** -++ * Puts a byte and a short into this byte vector. The byte vector is -++ * automatically enlarged if necessary. -++ * -++ * @param b -++ * a byte. -++ * @param s -++ * a short. -++ * @return this byte vector. -++ */ -++ ByteVector put12(final int b, final int s) { -++ int length = this.length; -++ if (length + 3 > data.length) { -++ enlarge(3); -++ } -++ byte[] data = this.data; -++ data[length++] = (byte) b; -++ data[length++] = (byte) (s >>> 8); -++ data[length++] = (byte) s; -++ this.length = length; -++ return this; -++ } -++ -++ /** -++ * Puts an int into this byte vector. The byte vector is automatically -++ * enlarged if necessary. -++ * -++ * @param i -++ * an int. -++ * @return this byte vector. -++ */ -++ public ByteVector putInt(final int i) { -++ int length = this.length; -++ if (length + 4 > data.length) { -++ enlarge(4); -++ } -++ byte[] data = this.data; -++ data[length++] = (byte) (i >>> 24); -++ data[length++] = (byte) (i >>> 16); -++ data[length++] = (byte) (i >>> 8); -++ data[length++] = (byte) i; -++ this.length = length; -++ return this; -++ } -++ -++ /** -++ * Puts a long into this byte vector. The byte vector is automatically -++ * enlarged if necessary. -++ * -++ * @param l -++ * a long. -++ * @return this byte vector. -++ */ -++ public ByteVector putLong(final long l) { -++ int length = this.length; -++ if (length + 8 > data.length) { -++ enlarge(8); -++ } -++ byte[] data = this.data; -++ int i = (int) (l >>> 32); -++ data[length++] = (byte) (i >>> 24); -++ data[length++] = (byte) (i >>> 16); -++ data[length++] = (byte) (i >>> 8); -++ data[length++] = (byte) i; -++ i = (int) l; -++ data[length++] = (byte) (i >>> 24); -++ data[length++] = (byte) (i >>> 16); -++ data[length++] = (byte) (i >>> 8); -++ data[length++] = (byte) i; -++ this.length = length; -++ return this; -++ } -++ -++ /** -++ * Puts an UTF8 string into this byte vector. The byte vector is -++ * automatically enlarged if necessary. -++ * -++ * @param s -++ * a String whose UTF8 encoded length must be less than 65536. -++ * @return this byte vector. -++ */ -++ public ByteVector putUTF8(final String s) { -++ int charLength = s.length(); -++ if (charLength > 65535) { -++ throw new IllegalArgumentException(); -++ } -++ int len = length; -++ if (len + 2 + charLength > data.length) { -++ enlarge(2 + charLength); -++ } -++ byte[] data = this.data; -++ // optimistic algorithm: instead of computing the byte length and then -++ // serializing the string (which requires two loops), we assume the byte -++ // length is equal to char length (which is the most frequent case), and -++ // we start serializing the string right away. During the serialization, -++ // if we find that this assumption is wrong, we continue with the -++ // general method. -++ data[len++] = (byte) (charLength >>> 8); -++ data[len++] = (byte) charLength; -++ for (int i = 0; i < charLength; ++i) { -++ char c = s.charAt(i); -++ if (c >= '\001' && c <= '\177') { -++ data[len++] = (byte) c; -++ } else { -++ length = len; -++ return encodeUTF8(s, i, 65535); -++ } -++ } -++ length = len; -++ return this; -++ } -++ -++ /** -++ * Puts an UTF8 string into this byte vector. The byte vector is -++ * automatically enlarged if necessary. The string length is encoded in two -++ * bytes before the encoded characters, if there is space for that (i.e. if -++ * this.length - i - 2 >= 0). -++ * -++ * @param s -++ * the String to encode. -++ * @param i -++ * the index of the first character to encode. The previous -++ * characters are supposed to have already been encoded, using -++ * only one byte per character. -++ * @param maxByteLength -++ * the maximum byte length of the encoded string, including the -++ * already encoded characters. -++ * @return this byte vector. -++ */ -++ ByteVector encodeUTF8(final String s, int i, int maxByteLength) { -++ int charLength = s.length(); -++ int byteLength = i; -++ char c; -++ for (int j = i; j < charLength; ++j) { -++ c = s.charAt(j); -++ if (c >= '\001' && c <= '\177') { -++ byteLength++; -++ } else if (c > '\u07FF') { -++ byteLength += 3; -++ } else { -++ byteLength += 2; -++ } -++ } -++ if (byteLength > maxByteLength) { -++ throw new IllegalArgumentException(); -++ } -++ int start = length - i - 2; -++ if (start >= 0) { -++ data[start] = (byte) (byteLength >>> 8); -++ data[start + 1] = (byte) byteLength; -++ } -++ if (length + byteLength - i > data.length) { -++ enlarge(byteLength - i); -++ } -++ int len = length; -++ for (int j = i; j < charLength; ++j) { -++ c = s.charAt(j); -++ if (c >= '\001' && c <= '\177') { -++ data[len++] = (byte) c; -++ } else if (c > '\u07FF') { -++ data[len++] = (byte) (0xE0 | c >> 12 & 0xF); -++ data[len++] = (byte) (0x80 | c >> 6 & 0x3F); -++ data[len++] = (byte) (0x80 | c & 0x3F); -++ } else { -++ data[len++] = (byte) (0xC0 | c >> 6 & 0x1F); -++ data[len++] = (byte) (0x80 | c & 0x3F); -++ } -++ } -++ length = len; -++ return this; -++ } -++ -++ /** -++ * Puts an array of bytes into this byte vector. The byte vector is -++ * automatically enlarged if necessary. -++ * -++ * @param b -++ * an array of bytes. May be <tt>null</tt> to put <tt>len</tt> -++ * null bytes into this byte vector. -++ * @param off -++ * index of the fist byte of b that must be copied. -++ * @param len -++ * number of bytes of b that must be copied. -++ * @return this byte vector. -++ */ -++ public ByteVector putByteArray(final byte[] b, final int off, final int len) { -++ if (length + len > data.length) { -++ enlarge(len); -++ } -++ if (b != null) { -++ System.arraycopy(b, off, data, length, len); -++ } -++ length += len; -++ return this; -++ } -++ -++ /** -++ * Enlarge this byte vector so that it can receive n more bytes. -++ * -++ * @param size -++ * number of additional bytes that this byte vector should be -++ * able to receive. -++ */ -++ private void enlarge(final int size) { -++ int length1 = 2 * data.length; -++ int length2 = length + size; -++ byte[] newData = new byte[length1 > length2 ? length1 : length2]; -++ System.arraycopy(data, 0, newData, 0, length); -++ data = newData; -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/ClassReader.java b/contrib/asm/src/org/objectweb/asm/ClassReader.java -+new file mode 100644 -+index 0000000..e23fd60 -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/ClassReader.java -+@@ -0,0 +1,2506 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++import java.io.IOException; -++import java.io.InputStream; -++ -++/** -++ * A Java class parser to make a {@link ClassVisitor} visit an existing class. -++ * This class parses a byte array conforming to the Java class file format and -++ * calls the appropriate visit methods of a given class visitor for each field, -++ * method and bytecode instruction encountered. -++ * -++ * @author Eric Bruneton -++ * @author Eugene Kuleshov -++ */ -++public class ClassReader { -++ -++ /** -++ * True to enable signatures support. -++ */ -++ static final boolean SIGNATURES = true; -++ -++ /** -++ * True to enable annotations support. -++ */ -++ static final boolean ANNOTATIONS = true; -++ -++ /** -++ * True to enable stack map frames support. -++ */ -++ static final boolean FRAMES = true; -++ -++ /** -++ * True to enable bytecode writing support. -++ */ -++ static final boolean WRITER = true; -++ -++ /** -++ * True to enable JSR_W and GOTO_W support. -++ */ -++ static final boolean RESIZE = true; -++ -++ /** -++ * Flag to skip method code. If this class is set <code>CODE</code> -++ * attribute won't be visited. This can be used, for example, to retrieve -++ * annotations for methods and method parameters. -++ */ -++ public static final int SKIP_CODE = 1; -++ -++ /** -++ * Flag to skip the debug information in the class. If this flag is set the -++ * debug information of the class is not visited, i.e. the -++ * {@link MethodVisitor#visitLocalVariable visitLocalVariable} and -++ * {@link MethodVisitor#visitLineNumber visitLineNumber} methods will not be -++ * called. -++ */ -++ public static final int SKIP_DEBUG = 2; -++ -++ /** -++ * Flag to skip the stack map frames in the class. If this flag is set the -++ * stack map frames of the class is not visited, i.e. the -++ * {@link MethodVisitor#visitFrame visitFrame} method will not be called. -++ * This flag is useful when the {@link ClassWriter#COMPUTE_FRAMES} option is -++ * used: it avoids visiting frames that will be ignored and recomputed from -++ * scratch in the class writer. -++ */ -++ public static final int SKIP_FRAMES = 4; -++ -++ /** -++ * Flag to expand the stack map frames. By default stack map frames are -++ * visited in their original format (i.e. "expanded" for classes whose -++ * version is less than V1_6, and "compressed" for the other classes). If -++ * this flag is set, stack map frames are always visited in expanded format -++ * (this option adds a decompression/recompression step in ClassReader and -++ * ClassWriter which degrades performances quite a lot). -++ */ -++ public static final int EXPAND_FRAMES = 8; -++ -++ /** -++ * The class to be parsed. <i>The content of this array must not be -++ * modified. This field is intended for {@link Attribute} sub classes, and -++ * is normally not needed by class generators or adapters.</i> -++ */ -++ public final byte[] b; -++ -++ /** -++ * The start index of each constant pool item in {@link #b b}, plus one. The -++ * one byte offset skips the constant pool item tag that indicates its type. -++ */ -++ private final int[] items; -++ -++ /** -++ * The String objects corresponding to the CONSTANT_Utf8 items. This cache -++ * avoids multiple parsing of a given CONSTANT_Utf8 constant pool item, -++ * which GREATLY improves performances (by a factor 2 to 3). This caching -++ * strategy could be extended to all constant pool items, but its benefit -++ * would not be so great for these items (because they are much less -++ * expensive to parse than CONSTANT_Utf8 items). -++ */ -++ private final String[] strings; -++ -++ /** -++ * Maximum length of the strings contained in the constant pool of the -++ * class. -++ */ -++ private final int maxStringLength; -++ -++ /** -++ * Start index of the class header information (access, name...) in -++ * {@link #b b}. -++ */ -++ public final int header; -++ -++ // ------------------------------------------------------------------------ -++ // Constructors -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Constructs a new {@link ClassReader} object. -++ * -++ * @param b -++ * the bytecode of the class to be read. -++ */ -++ public ClassReader(final byte[] b) { -++ this(b, 0, b.length); -++ } -++ -++ /** -++ * Constructs a new {@link ClassReader} object. -++ * -++ * @param b -++ * the bytecode of the class to be read. -++ * @param off -++ * the start offset of the class data. -++ * @param len -++ * the length of the class data. -++ */ -++ public ClassReader(final byte[] b, final int off, final int len) { -++ this.b = b; -++ // checks the class version -++ if (readShort(off + 6) > Opcodes.V1_8) { -++ throw new IllegalArgumentException(); -++ } -++ // parses the constant pool -++ items = new int[readUnsignedShort(off + 8)]; -++ int n = items.length; -++ strings = new String[n]; -++ int max = 0; -++ int index = off + 10; -++ for (int i = 1; i < n; ++i) { -++ items[i] = index + 1; -++ int size; -++ switch (b[index]) { -++ case ClassWriter.FIELD: -++ case ClassWriter.METH: -++ case ClassWriter.IMETH: -++ case ClassWriter.INT: -++ case ClassWriter.FLOAT: -++ case ClassWriter.NAME_TYPE: -++ case ClassWriter.INDY: -++ size = 5; -++ break; -++ case ClassWriter.LONG: -++ case ClassWriter.DOUBLE: -++ size = 9; -++ ++i; -++ break; -++ case ClassWriter.UTF8: -++ size = 3 + readUnsignedShort(index + 1); -++ if (size > max) { -++ max = size; -++ } -++ break; -++ case ClassWriter.HANDLE: -++ size = 4; -++ break; -++ // case ClassWriter.CLASS: -++ // case ClassWriter.STR: -++ // case ClassWriter.MTYPE -++ default: -++ size = 3; -++ break; -++ } -++ index += size; -++ } -++ maxStringLength = max; -++ // the class header information starts just after the constant pool -++ header = index; -++ } -++ -++ /** -++ * Returns the class's access flags (see {@link Opcodes}). This value may -++ * not reflect Deprecated and Synthetic flags when bytecode is before 1.5 -++ * and those flags are represented by attributes. -++ * -++ * @return the class access flags -++ * -++ * @see ClassVisitor#visit(int, int, String, String, String, String[]) -++ */ -++ public int getAccess() { -++ return readUnsignedShort(header); -++ } -++ -++ /** -++ * Returns the internal name of the class (see -++ * {@link Type#getInternalName() getInternalName}). -++ * -++ * @return the internal class name -++ * -++ * @see ClassVisitor#visit(int, int, String, String, String, String[]) -++ */ -++ public String getClassName() { -++ return readClass(header + 2, new char[maxStringLength]); -++ } -++ -++ /** -++ * Returns the internal of name of the super class (see -++ * {@link Type#getInternalName() getInternalName}). For interfaces, the -++ * super class is {@link Object}. -++ * -++ * @return the internal name of super class, or <tt>null</tt> for -++ * {@link Object} class. -++ * -++ * @see ClassVisitor#visit(int, int, String, String, String, String[]) -++ */ -++ public String getSuperName() { -++ return readClass(header + 4, new char[maxStringLength]); -++ } -++ -++ /** -++ * Returns the internal names of the class's interfaces (see -++ * {@link Type#getInternalName() getInternalName}). -++ * -++ * @return the array of internal names for all implemented interfaces or -++ * <tt>null</tt>. -++ * -++ * @see ClassVisitor#visit(int, int, String, String, String, String[]) -++ */ -++ public String[] getInterfaces() { -++ int index = header + 6; -++ int n = readUnsignedShort(index); -++ String[] interfaces = new String[n]; -++ if (n > 0) { -++ char[] buf = new char[maxStringLength]; -++ for (int i = 0; i < n; ++i) { -++ index += 2; -++ interfaces[i] = readClass(index, buf); -++ } -++ } -++ return interfaces; -++ } -++ -++ /** -++ * Copies the constant pool data into the given {@link ClassWriter}. Should -++ * be called before the {@link #accept(ClassVisitor,int)} method. -++ * -++ * @param classWriter -++ * the {@link ClassWriter} to copy constant pool into. -++ */ -++ void copyPool(final ClassWriter classWriter) { -++ char[] buf = new char[maxStringLength]; -++ int ll = items.length; -++ Item[] items2 = new Item[ll]; -++ for (int i = 1; i < ll; i++) { -++ int index = items[i]; -++ int tag = b[index - 1]; -++ Item item = new Item(i); -++ int nameType; -++ switch (tag) { -++ case ClassWriter.FIELD: -++ case ClassWriter.METH: -++ case ClassWriter.IMETH: -++ nameType = items[readUnsignedShort(index + 2)]; -++ item.set(tag, readClass(index, buf), readUTF8(nameType, buf), -++ readUTF8(nameType + 2, buf)); -++ break; -++ case ClassWriter.INT: -++ item.set(readInt(index)); -++ break; -++ case ClassWriter.FLOAT: -++ item.set(Float.intBitsToFloat(readInt(index))); -++ break; -++ case ClassWriter.NAME_TYPE: -++ item.set(tag, readUTF8(index, buf), readUTF8(index + 2, buf), -++ null); -++ break; -++ case ClassWriter.LONG: -++ item.set(readLong(index)); -++ ++i; -++ break; -++ case ClassWriter.DOUBLE: -++ item.set(Double.longBitsToDouble(readLong(index))); -++ ++i; -++ break; -++ case ClassWriter.UTF8: { -++ String s = strings[i]; -++ if (s == null) { -++ index = items[i]; -++ s = strings[i] = readUTF(index + 2, -++ readUnsignedShort(index), buf); -++ } -++ item.set(tag, s, null, null); -++ break; -++ } -++ case ClassWriter.HANDLE: { -++ int fieldOrMethodRef = items[readUnsignedShort(index + 1)]; -++ nameType = items[readUnsignedShort(fieldOrMethodRef + 2)]; -++ item.set(ClassWriter.HANDLE_BASE + readByte(index), -++ readClass(fieldOrMethodRef, buf), -++ readUTF8(nameType, buf), readUTF8(nameType + 2, buf)); -++ break; -++ } -++ case ClassWriter.INDY: -++ if (classWriter.bootstrapMethods == null) { -++ copyBootstrapMethods(classWriter, items2, buf); -++ } -++ nameType = items[readUnsignedShort(index + 2)]; -++ item.set(readUTF8(nameType, buf), readUTF8(nameType + 2, buf), -++ readUnsignedShort(index)); -++ break; -++ // case ClassWriter.STR: -++ // case ClassWriter.CLASS: -++ // case ClassWriter.MTYPE -++ default: -++ item.set(tag, readUTF8(index, buf), null, null); -++ break; -++ } -++ -++ int index2 = item.hashCode % items2.length; -++ item.next = items2[index2]; -++ items2[index2] = item; -++ } -++ -++ int off = items[1] - 1; -++ classWriter.pool.putByteArray(b, off, header - off); -++ classWriter.items = items2; -++ classWriter.threshold = (int) (0.75d * ll); -++ classWriter.index = ll; -++ } -++ -++ /** -++ * Copies the bootstrap method data into the given {@link ClassWriter}. -++ * Should be called before the {@link #accept(ClassVisitor,int)} method. -++ * -++ * @param classWriter -++ * the {@link ClassWriter} to copy bootstrap methods into. -++ */ -++ private void copyBootstrapMethods(final ClassWriter classWriter, -++ final Item[] items, final char[] c) { -++ // finds the "BootstrapMethods" attribute -++ int u = getAttributes(); -++ boolean found = false; -++ for (int i = readUnsignedShort(u); i > 0; --i) { -++ String attrName = readUTF8(u + 2, c); -++ if ("BootstrapMethods".equals(attrName)) { -++ found = true; -++ break; -++ } -++ u += 6 + readInt(u + 4); -++ } -++ if (!found) { -++ return; -++ } -++ // copies the bootstrap methods in the class writer -++ int boostrapMethodCount = readUnsignedShort(u + 8); -++ for (int j = 0, v = u + 10; j < boostrapMethodCount; j++) { -++ int position = v - u - 10; -++ int hashCode = readConst(readUnsignedShort(v), c).hashCode(); -++ for (int k = readUnsignedShort(v + 2); k > 0; --k) { -++ hashCode ^= readConst(readUnsignedShort(v + 4), c).hashCode(); -++ v += 2; -++ } -++ v += 4; -++ Item item = new Item(j); -++ item.set(position, hashCode & 0x7FFFFFFF); -++ int index = item.hashCode % items.length; -++ item.next = items[index]; -++ items[index] = item; -++ } -++ int attrSize = readInt(u + 4); -++ ByteVector bootstrapMethods = new ByteVector(attrSize + 62); -++ bootstrapMethods.putByteArray(b, u + 10, attrSize - 2); -++ classWriter.bootstrapMethodsCount = boostrapMethodCount; -++ classWriter.bootstrapMethods = bootstrapMethods; -++ } -++ -++ /** -++ * Constructs a new {@link ClassReader} object. -++ * -++ * @param is -++ * an input stream from which to read the class. -++ * @throws IOException -++ * if a problem occurs during reading. -++ */ -++ public ClassReader(final InputStream is) throws IOException { -++ this(readClass(is, false)); -++ } -++ -++ /** -++ * Constructs a new {@link ClassReader} object. -++ * -++ * @param name -++ * the binary qualified name of the class to be read. -++ * @throws IOException -++ * if an exception occurs during reading. -++ */ -++ public ClassReader(final String name) throws IOException { -++ this(readClass( -++ ClassLoader.getSystemResourceAsStream(name.replace('.', '/') -++ + ".class"), true)); -++ } -++ -++ /** -++ * Reads the bytecode of a class. -++ * -++ * @param is -++ * an input stream from which to read the class. -++ * @param close -++ * true to close the input stream after reading. -++ * @return the bytecode read from the given input stream. -++ * @throws IOException -++ * if a problem occurs during reading. -++ */ -++ private static byte[] readClass(final InputStream is, boolean close) -++ throws IOException { -++ if (is == null) { -++ throw new IOException("Class not found"); -++ } -++ try { -++ byte[] b = new byte[is.available()]; -++ int len = 0; -++ while (true) { -++ int n = is.read(b, len, b.length - len); -++ if (n == -1) { -++ if (len < b.length) { -++ byte[] c = new byte[len]; -++ System.arraycopy(b, 0, c, 0, len); -++ b = c; -++ } -++ return b; -++ } -++ len += n; -++ if (len == b.length) { -++ int last = is.read(); -++ if (last < 0) { -++ return b; -++ } -++ byte[] c = new byte[b.length + 1000]; -++ System.arraycopy(b, 0, c, 0, len); -++ c[len++] = (byte) last; -++ b = c; -++ } -++ } -++ } finally { -++ if (close) { -++ is.close(); -++ } -++ } -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Public methods -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Makes the given visitor visit the Java class of this {@link ClassReader} -++ * . This class is the one specified in the constructor (see -++ * {@link #ClassReader(byte[]) ClassReader}). -++ * -++ * @param classVisitor -++ * the visitor that must visit this class. -++ * @param flags -++ * option flags that can be used to modify the default behavior -++ * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES} -++ * , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}. -++ */ -++ public void accept(final ClassVisitor classVisitor, final int flags) { -++ accept(classVisitor, new Attribute[0], flags); -++ } -++ -++ /** -++ * Makes the given visitor visit the Java class of this {@link ClassReader}. -++ * This class is the one specified in the constructor (see -++ * {@link #ClassReader(byte[]) ClassReader}). -++ * -++ * @param classVisitor -++ * the visitor that must visit this class. -++ * @param attrs -++ * prototypes of the attributes that must be parsed during the -++ * visit of the class. Any attribute whose type is not equal to -++ * the type of one the prototypes will not be parsed: its byte -++ * array value will be passed unchanged to the ClassWriter. -++ * <i>This may corrupt it if this value contains references to -++ * the constant pool, or has syntactic or semantic links with a -++ * class element that has been transformed by a class adapter -++ * between the reader and the writer</i>. -++ * @param flags -++ * option flags that can be used to modify the default behavior -++ * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES} -++ * , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}. -++ */ -++ public void accept(final ClassVisitor classVisitor, -++ final Attribute[] attrs, final int flags) { -++ int u = header; // current offset in the class file -++ char[] c = new char[maxStringLength]; // buffer used to read strings -++ -++ Context context = new Context(); -++ context.attrs = attrs; -++ context.flags = flags; -++ context.buffer = c; -++ -++ // reads the class declaration -++ int access = readUnsignedShort(u); -++ String name = readClass(u + 2, c); -++ String superClass = readClass(u + 4, c); -++ String[] interfaces = new String[readUnsignedShort(u + 6)]; -++ u += 8; -++ for (int i = 0; i < interfaces.length; ++i) { -++ interfaces[i] = readClass(u, c); -++ u += 2; -++ } -++ -++ // reads the class attributes -++ String signature = null; -++ String sourceFile = null; -++ String sourceDebug = null; -++ String enclosingOwner = null; -++ String enclosingName = null; -++ String enclosingDesc = null; -++ int anns = 0; -++ int ianns = 0; -++ int tanns = 0; -++ int itanns = 0; -++ int innerClasses = 0; -++ Attribute attributes = null; -++ -++ u = getAttributes(); -++ for (int i = readUnsignedShort(u); i > 0; --i) { -++ String attrName = readUTF8(u + 2, c); -++ // tests are sorted in decreasing frequency order -++ // (based on frequencies observed on typical classes) -++ if ("SourceFile".equals(attrName)) { -++ sourceFile = readUTF8(u + 8, c); -++ } else if ("InnerClasses".equals(attrName)) { -++ innerClasses = u + 8; -++ } else if ("EnclosingMethod".equals(attrName)) { -++ enclosingOwner = readClass(u + 8, c); -++ int item = readUnsignedShort(u + 10); -++ if (item != 0) { -++ enclosingName = readUTF8(items[item], c); -++ enclosingDesc = readUTF8(items[item] + 2, c); -++ } -++ } else if (SIGNATURES && "Signature".equals(attrName)) { -++ signature = readUTF8(u + 8, c); -++ } else if (ANNOTATIONS -++ && "RuntimeVisibleAnnotations".equals(attrName)) { -++ anns = u + 8; -++ } else if (ANNOTATIONS -++ && "RuntimeVisibleTypeAnnotations".equals(attrName)) { -++ tanns = u + 8; -++ } else if ("Deprecated".equals(attrName)) { -++ access |= Opcodes.ACC_DEPRECATED; -++ } else if ("Synthetic".equals(attrName)) { -++ access |= Opcodes.ACC_SYNTHETIC -++ | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; -++ } else if ("SourceDebugExtension".equals(attrName)) { -++ int len = readInt(u + 4); -++ sourceDebug = readUTF(u + 8, len, new char[len]); -++ } else if (ANNOTATIONS -++ && "RuntimeInvisibleAnnotations".equals(attrName)) { -++ ianns = u + 8; -++ } else if (ANNOTATIONS -++ && "RuntimeInvisibleTypeAnnotations".equals(attrName)) { -++ itanns = u + 8; -++ } else if ("BootstrapMethods".equals(attrName)) { -++ int[] bootstrapMethods = new int[readUnsignedShort(u + 8)]; -++ for (int j = 0, v = u + 10; j < bootstrapMethods.length; j++) { -++ bootstrapMethods[j] = v; -++ v += 2 + readUnsignedShort(v + 2) << 1; -++ } -++ context.bootstrapMethods = bootstrapMethods; -++ } else { -++ Attribute attr = readAttribute(attrs, attrName, u + 8, -++ readInt(u + 4), c, -1, null); -++ if (attr != null) { -++ attr.next = attributes; -++ attributes = attr; -++ } -++ } -++ u += 6 + readInt(u + 4); -++ } -++ -++ // visits the class declaration -++ classVisitor.visit(readInt(items[1] - 7), access, name, signature, -++ superClass, interfaces); -++ -++ // visits the source and debug info -++ if ((flags & SKIP_DEBUG) == 0 -++ && (sourceFile != null || sourceDebug != null)) { -++ classVisitor.visitSource(sourceFile, sourceDebug); -++ } -++ -++ // visits the outer class -++ if (enclosingOwner != null) { -++ classVisitor.visitOuterClass(enclosingOwner, enclosingName, -++ enclosingDesc); -++ } -++ -++ // visits the class annotations and type annotations -++ if (ANNOTATIONS && anns != 0) { -++ for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) { -++ v = readAnnotationValues(v + 2, c, true, -++ classVisitor.visitAnnotation(readUTF8(v, c), true)); -++ } -++ } -++ if (ANNOTATIONS && ianns != 0) { -++ for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) { -++ v = readAnnotationValues(v + 2, c, true, -++ classVisitor.visitAnnotation(readUTF8(v, c), false)); -++ } -++ } -++ if (ANNOTATIONS && tanns != 0) { -++ for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { -++ v = readAnnotationTarget(context, v); -++ v = readAnnotationValues(v + 2, c, true, -++ classVisitor.visitTypeAnnotation(context.typeRef, -++ context.typePath, readUTF8(v, c), true)); -++ } -++ } -++ if (ANNOTATIONS && itanns != 0) { -++ for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { -++ v = readAnnotationTarget(context, v); -++ v = readAnnotationValues(v + 2, c, true, -++ classVisitor.visitTypeAnnotation(context.typeRef, -++ context.typePath, readUTF8(v, c), false)); -++ } -++ } -++ -++ // visits the attributes -++ while (attributes != null) { -++ Attribute attr = attributes.next; -++ attributes.next = null; -++ classVisitor.visitAttribute(attributes); -++ attributes = attr; -++ } -++ -++ // visits the inner classes -++ if (innerClasses != 0) { -++ int v = innerClasses + 2; -++ for (int i = readUnsignedShort(innerClasses); i > 0; --i) { -++ classVisitor.visitInnerClass(readClass(v, c), -++ readClass(v + 2, c), readUTF8(v + 4, c), -++ readUnsignedShort(v + 6)); -++ v += 8; -++ } -++ } -++ -++ // visits the fields and methods -++ u = header + 10 + 2 * interfaces.length; -++ for (int i = readUnsignedShort(u - 2); i > 0; --i) { -++ u = readField(classVisitor, context, u); -++ } -++ u += 2; -++ for (int i = readUnsignedShort(u - 2); i > 0; --i) { -++ u = readMethod(classVisitor, context, u); -++ } -++ -++ // visits the end of the class -++ classVisitor.visitEnd(); -++ } -++ -++ /** -++ * Reads a field and makes the given visitor visit it. -++ * -++ * @param classVisitor -++ * the visitor that must visit the field. -++ * @param context -++ * information about the class being parsed. -++ * @param u -++ * the start offset of the field in the class file. -++ * @return the offset of the first byte following the field in the class. -++ */ -++ private int readField(final ClassVisitor classVisitor, -++ final Context context, int u) { -++ // reads the field declaration -++ char[] c = context.buffer; -++ int access = readUnsignedShort(u); -++ String name = readUTF8(u + 2, c); -++ String desc = readUTF8(u + 4, c); -++ u += 6; -++ -++ // reads the field attributes -++ String signature = null; -++ int anns = 0; -++ int ianns = 0; -++ int tanns = 0; -++ int itanns = 0; -++ Object value = null; -++ Attribute attributes = null; -++ -++ for (int i = readUnsignedShort(u); i > 0; --i) { -++ String attrName = readUTF8(u + 2, c); -++ // tests are sorted in decreasing frequency order -++ // (based on frequencies observed on typical classes) -++ if ("ConstantValue".equals(attrName)) { -++ int item = readUnsignedShort(u + 8); -++ value = item == 0 ? null : readConst(item, c); -++ } else if (SIGNATURES && "Signature".equals(attrName)) { -++ signature = readUTF8(u + 8, c); -++ } else if ("Deprecated".equals(attrName)) { -++ access |= Opcodes.ACC_DEPRECATED; -++ } else if ("Synthetic".equals(attrName)) { -++ access |= Opcodes.ACC_SYNTHETIC -++ | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; -++ } else if (ANNOTATIONS -++ && "RuntimeVisibleAnnotations".equals(attrName)) { -++ anns = u + 8; -++ } else if (ANNOTATIONS -++ && "RuntimeVisibleTypeAnnotations".equals(attrName)) { -++ tanns = u + 8; -++ } else if (ANNOTATIONS -++ && "RuntimeInvisibleAnnotations".equals(attrName)) { -++ ianns = u + 8; -++ } else if (ANNOTATIONS -++ && "RuntimeInvisibleTypeAnnotations".equals(attrName)) { -++ itanns = u + 8; -++ } else { -++ Attribute attr = readAttribute(context.attrs, attrName, u + 8, -++ readInt(u + 4), c, -1, null); -++ if (attr != null) { -++ attr.next = attributes; -++ attributes = attr; -++ } -++ } -++ u += 6 + readInt(u + 4); -++ } -++ u += 2; -++ -++ // visits the field declaration -++ FieldVisitor fv = classVisitor.visitField(access, name, desc, -++ signature, value); -++ if (fv == null) { -++ return u; -++ } -++ -++ // visits the field annotations and type annotations -++ if (ANNOTATIONS && anns != 0) { -++ for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) { -++ v = readAnnotationValues(v + 2, c, true, -++ fv.visitAnnotation(readUTF8(v, c), true)); -++ } -++ } -++ if (ANNOTATIONS && ianns != 0) { -++ for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) { -++ v = readAnnotationValues(v + 2, c, true, -++ fv.visitAnnotation(readUTF8(v, c), false)); -++ } -++ } -++ if (ANNOTATIONS && tanns != 0) { -++ for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { -++ v = readAnnotationTarget(context, v); -++ v = readAnnotationValues(v + 2, c, true, -++ fv.visitTypeAnnotation(context.typeRef, -++ context.typePath, readUTF8(v, c), true)); -++ } -++ } -++ if (ANNOTATIONS && itanns != 0) { -++ for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { -++ v = readAnnotationTarget(context, v); -++ v = readAnnotationValues(v + 2, c, true, -++ fv.visitTypeAnnotation(context.typeRef, -++ context.typePath, readUTF8(v, c), false)); -++ } -++ } -++ -++ // visits the field attributes -++ while (attributes != null) { -++ Attribute attr = attributes.next; -++ attributes.next = null; -++ fv.visitAttribute(attributes); -++ attributes = attr; -++ } -++ -++ // visits the end of the field -++ fv.visitEnd(); -++ -++ return u; -++ } -++ -++ /** -++ * Reads a method and makes the given visitor visit it. -++ * -++ * @param classVisitor -++ * the visitor that must visit the method. -++ * @param context -++ * information about the class being parsed. -++ * @param u -++ * the start offset of the method in the class file. -++ * @return the offset of the first byte following the method in the class. -++ */ -++ private int readMethod(final ClassVisitor classVisitor, -++ final Context context, int u) { -++ // reads the method declaration -++ char[] c = context.buffer; -++ context.access = readUnsignedShort(u); -++ context.name = readUTF8(u + 2, c); -++ context.desc = readUTF8(u + 4, c); -++ u += 6; -++ -++ // reads the method attributes -++ int code = 0; -++ int exception = 0; -++ String[] exceptions = null; -++ String signature = null; -++ int methodParameters = 0; -++ int anns = 0; -++ int ianns = 0; -++ int tanns = 0; -++ int itanns = 0; -++ int dann = 0; -++ int mpanns = 0; -++ int impanns = 0; -++ int firstAttribute = u; -++ Attribute attributes = null; -++ -++ for (int i = readUnsignedShort(u); i > 0; --i) { -++ String attrName = readUTF8(u + 2, c); -++ // tests are sorted in decreasing frequency order -++ // (based on frequencies observed on typical classes) -++ if ("Code".equals(attrName)) { -++ if ((context.flags & SKIP_CODE) == 0) { -++ code = u + 8; -++ } -++ } else if ("Exceptions".equals(attrName)) { -++ exceptions = new String[readUnsignedShort(u + 8)]; -++ exception = u + 10; -++ for (int j = 0; j < exceptions.length; ++j) { -++ exceptions[j] = readClass(exception, c); -++ exception += 2; -++ } -++ } else if (SIGNATURES && "Signature".equals(attrName)) { -++ signature = readUTF8(u + 8, c); -++ } else if ("Deprecated".equals(attrName)) { -++ context.access |= Opcodes.ACC_DEPRECATED; -++ } else if (ANNOTATIONS -++ && "RuntimeVisibleAnnotations".equals(attrName)) { -++ anns = u + 8; -++ } else if (ANNOTATIONS -++ && "RuntimeVisibleTypeAnnotations".equals(attrName)) { -++ tanns = u + 8; -++ } else if (ANNOTATIONS && "AnnotationDefault".equals(attrName)) { -++ dann = u + 8; -++ } else if ("Synthetic".equals(attrName)) { -++ context.access |= Opcodes.ACC_SYNTHETIC -++ | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; -++ } else if (ANNOTATIONS -++ && "RuntimeInvisibleAnnotations".equals(attrName)) { -++ ianns = u + 8; -++ } else if (ANNOTATIONS -++ && "RuntimeInvisibleTypeAnnotations".equals(attrName)) { -++ itanns = u + 8; -++ } else if (ANNOTATIONS -++ && "RuntimeVisibleParameterAnnotations".equals(attrName)) { -++ mpanns = u + 8; -++ } else if (ANNOTATIONS -++ && "RuntimeInvisibleParameterAnnotations".equals(attrName)) { -++ impanns = u + 8; -++ } else if ("MethodParameters".equals(attrName)) { -++ methodParameters = u + 8; -++ } else { -++ Attribute attr = readAttribute(context.attrs, attrName, u + 8, -++ readInt(u + 4), c, -1, null); -++ if (attr != null) { -++ attr.next = attributes; -++ attributes = attr; -++ } -++ } -++ u += 6 + readInt(u + 4); -++ } -++ u += 2; -++ -++ // visits the method declaration -++ MethodVisitor mv = classVisitor.visitMethod(context.access, -++ context.name, context.desc, signature, exceptions); -++ if (mv == null) { -++ return u; -++ } -++ -++ /* -++ * if the returned MethodVisitor is in fact a MethodWriter, it means -++ * there is no method adapter between the reader and the writer. If, in -++ * addition, the writer's constant pool was copied from this reader -++ * (mw.cw.cr == this), and the signature and exceptions of the method -++ * have not been changed, then it is possible to skip all visit events -++ * and just copy the original code of the method to the writer (the -++ * access, name and descriptor can have been changed, this is not -++ * important since they are not copied as is from the reader). -++ */ -++ if (WRITER && mv instanceof MethodWriter) { -++ MethodWriter mw = (MethodWriter) mv; -++ if (mw.cw.cr == this && signature == mw.signature) { -++ boolean sameExceptions = false; -++ if (exceptions == null) { -++ sameExceptions = mw.exceptionCount == 0; -++ } else if (exceptions.length == mw.exceptionCount) { -++ sameExceptions = true; -++ for (int j = exceptions.length - 1; j >= 0; --j) { -++ exception -= 2; -++ if (mw.exceptions[j] != readUnsignedShort(exception)) { -++ sameExceptions = false; -++ break; -++ } -++ } -++ } -++ if (sameExceptions) { -++ /* -++ * we do not copy directly the code into MethodWriter to -++ * save a byte array copy operation. The real copy will be -++ * done in ClassWriter.toByteArray(). -++ */ -++ mw.classReaderOffset = firstAttribute; -++ mw.classReaderLength = u - firstAttribute; -++ return u; -++ } -++ } -++ } -++ -++ // visit the method parameters -++ if (methodParameters != 0) { -++ for (int i = b[methodParameters] & 0xFF, v = methodParameters + 1; i > 0; --i, v = v + 4) { -++ mv.visitParameter(readUTF8(v, c), readUnsignedShort(v + 2)); -++ } -++ } -++ -++ // visits the method annotations -++ if (ANNOTATIONS && dann != 0) { -++ AnnotationVisitor dv = mv.visitAnnotationDefault(); -++ readAnnotationValue(dann, c, null, dv); -++ if (dv != null) { -++ dv.visitEnd(); -++ } -++ } -++ if (ANNOTATIONS && anns != 0) { -++ for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) { -++ v = readAnnotationValues(v + 2, c, true, -++ mv.visitAnnotation(readUTF8(v, c), true)); -++ } -++ } -++ if (ANNOTATIONS && ianns != 0) { -++ for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) { -++ v = readAnnotationValues(v + 2, c, true, -++ mv.visitAnnotation(readUTF8(v, c), false)); -++ } -++ } -++ if (ANNOTATIONS && tanns != 0) { -++ for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) { -++ v = readAnnotationTarget(context, v); -++ v = readAnnotationValues(v + 2, c, true, -++ mv.visitTypeAnnotation(context.typeRef, -++ context.typePath, readUTF8(v, c), true)); -++ } -++ } -++ if (ANNOTATIONS && itanns != 0) { -++ for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) { -++ v = readAnnotationTarget(context, v); -++ v = readAnnotationValues(v + 2, c, true, -++ mv.visitTypeAnnotation(context.typeRef, -++ context.typePath, readUTF8(v, c), false)); -++ } -++ } -++ if (ANNOTATIONS && mpanns != 0) { -++ readParameterAnnotations(mv, context, mpanns, true); -++ } -++ if (ANNOTATIONS && impanns != 0) { -++ readParameterAnnotations(mv, context, impanns, false); -++ } -++ -++ // visits the method attributes -++ while (attributes != null) { -++ Attribute attr = attributes.next; -++ attributes.next = null; -++ mv.visitAttribute(attributes); -++ attributes = attr; -++ } -++ -++ // visits the method code -++ if (code != 0) { -++ mv.visitCode(); -++ readCode(mv, context, code); -++ } -++ -++ // visits the end of the method -++ mv.visitEnd(); -++ -++ return u; -++ } -++ -++ /** -++ * Reads the bytecode of a method and makes the given visitor visit it. -++ * -++ * @param mv -++ * the visitor that must visit the method's code. -++ * @param context -++ * information about the class being parsed. -++ * @param u -++ * the start offset of the code attribute in the class file. -++ */ -++ private void readCode(final MethodVisitor mv, final Context context, int u) { -++ // reads the header -++ byte[] b = this.b; -++ char[] c = context.buffer; -++ int maxStack = readUnsignedShort(u); -++ int maxLocals = readUnsignedShort(u + 2); -++ int codeLength = readInt(u + 4); -++ u += 8; -++ -++ // reads the bytecode to find the labels -++ int codeStart = u; -++ int codeEnd = u + codeLength; -++ Label[] labels = context.labels = new Label[codeLength + 2]; -++ readLabel(codeLength + 1, labels); -++ while (u < codeEnd) { -++ int offset = u - codeStart; -++ int opcode = b[u] & 0xFF; -++ switch (ClassWriter.TYPE[opcode]) { -++ case ClassWriter.NOARG_INSN: -++ case ClassWriter.IMPLVAR_INSN: -++ u += 1; -++ break; -++ case ClassWriter.LABEL_INSN: -++ readLabel(offset + readShort(u + 1), labels); -++ u += 3; -++ break; -++ case ClassWriter.LABELW_INSN: -++ readLabel(offset + readInt(u + 1), labels); -++ u += 5; -++ break; -++ case ClassWriter.WIDE_INSN: -++ opcode = b[u + 1] & 0xFF; -++ if (opcode == Opcodes.IINC) { -++ u += 6; -++ } else { -++ u += 4; -++ } -++ break; -++ case ClassWriter.TABL_INSN: -++ // skips 0 to 3 padding bytes -++ u = u + 4 - (offset & 3); -++ // reads instruction -++ readLabel(offset + readInt(u), labels); -++ for (int i = readInt(u + 8) - readInt(u + 4) + 1; i > 0; --i) { -++ readLabel(offset + readInt(u + 12), labels); -++ u += 4; -++ } -++ u += 12; -++ break; -++ case ClassWriter.LOOK_INSN: -++ // skips 0 to 3 padding bytes -++ u = u + 4 - (offset & 3); -++ // reads instruction -++ readLabel(offset + readInt(u), labels); -++ for (int i = readInt(u + 4); i > 0; --i) { -++ readLabel(offset + readInt(u + 12), labels); -++ u += 8; -++ } -++ u += 8; -++ break; -++ case ClassWriter.VAR_INSN: -++ case ClassWriter.SBYTE_INSN: -++ case ClassWriter.LDC_INSN: -++ u += 2; -++ break; -++ case ClassWriter.SHORT_INSN: -++ case ClassWriter.LDCW_INSN: -++ case ClassWriter.FIELDORMETH_INSN: -++ case ClassWriter.TYPE_INSN: -++ case ClassWriter.IINC_INSN: -++ u += 3; -++ break; -++ case ClassWriter.ITFMETH_INSN: -++ case ClassWriter.INDYMETH_INSN: -++ u += 5; -++ break; -++ // case MANA_INSN: -++ default: -++ u += 4; -++ break; -++ } -++ } -++ -++ // reads the try catch entries to find the labels, and also visits them -++ for (int i = readUnsignedShort(u); i > 0; --i) { -++ Label start = readLabel(readUnsignedShort(u + 2), labels); -++ Label end = readLabel(readUnsignedShort(u + 4), labels); -++ Label handler = readLabel(readUnsignedShort(u + 6), labels); -++ String type = readUTF8(items[readUnsignedShort(u + 8)], c); -++ mv.visitTryCatchBlock(start, end, handler, type); -++ u += 8; -++ } -++ u += 2; -++ -++ // reads the code attributes -++ int[] tanns = null; // start index of each visible type annotation -++ int[] itanns = null; // start index of each invisible type annotation -++ int tann = 0; // current index in tanns array -++ int itann = 0; // current index in itanns array -++ int ntoff = -1; // next visible type annotation code offset -++ int nitoff = -1; // next invisible type annotation code offset -++ int varTable = 0; -++ int varTypeTable = 0; -++ boolean zip = true; -++ boolean unzip = (context.flags & EXPAND_FRAMES) != 0; -++ int stackMap = 0; -++ int stackMapSize = 0; -++ int frameCount = 0; -++ Context frame = null; -++ Attribute attributes = null; -++ -++ for (int i = readUnsignedShort(u); i > 0; --i) { -++ String attrName = readUTF8(u + 2, c); -++ if ("LocalVariableTable".equals(attrName)) { -++ if ((context.flags & SKIP_DEBUG) == 0) { -++ varTable = u + 8; -++ for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) { -++ int label = readUnsignedShort(v + 10); -++ if (labels[label] == null) { -++ readLabel(label, labels).status |= Label.DEBUG; -++ } -++ label += readUnsignedShort(v + 12); -++ if (labels[label] == null) { -++ readLabel(label, labels).status |= Label.DEBUG; -++ } -++ v += 10; -++ } -++ } -++ } else if ("LocalVariableTypeTable".equals(attrName)) { -++ varTypeTable = u + 8; -++ } else if ("LineNumberTable".equals(attrName)) { -++ if ((context.flags & SKIP_DEBUG) == 0) { -++ for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) { -++ int label = readUnsignedShort(v + 10); -++ if (labels[label] == null) { -++ readLabel(label, labels).status |= Label.DEBUG; -++ } -++ Label l = labels[label]; -++ while (l.line > 0) { -++ if (l.next == null) { -++ l.next = new Label(); -++ } -++ l = l.next; -++ } -++ l.line = readUnsignedShort(v + 12); -++ v += 4; -++ } -++ } -++ } else if (ANNOTATIONS -++ && "RuntimeVisibleTypeAnnotations".equals(attrName)) { -++ tanns = readTypeAnnotations(mv, context, u + 8, true); -++ ntoff = tanns.length == 0 || readByte(tanns[0]) < 0x43 ? -1 -++ : readUnsignedShort(tanns[0] + 1); -++ } else if (ANNOTATIONS -++ && "RuntimeInvisibleTypeAnnotations".equals(attrName)) { -++ itanns = readTypeAnnotations(mv, context, u + 8, false); -++ nitoff = itanns.length == 0 || readByte(itanns[0]) < 0x43 ? -1 -++ : readUnsignedShort(itanns[0] + 1); -++ } else if (FRAMES && "StackMapTable".equals(attrName)) { -++ if ((context.flags & SKIP_FRAMES) == 0) { -++ stackMap = u + 10; -++ stackMapSize = readInt(u + 4); -++ frameCount = readUnsignedShort(u + 8); -++ } -++ /* -++ * here we do not extract the labels corresponding to the -++ * attribute content. This would require a full parsing of the -++ * attribute, which would need to be repeated in the second -++ * phase (see below). Instead the content of the attribute is -++ * read one frame at a time (i.e. after a frame has been -++ * visited, the next frame is read), and the labels it contains -++ * are also extracted one frame at a time. Thanks to the -++ * ordering of frames, having only a "one frame lookahead" is -++ * not a problem, i.e. it is not possible to see an offset -++ * smaller than the offset of the current insn and for which no -++ * Label exist. -++ */ -++ /* -++ * This is not true for UNINITIALIZED type offsets. We solve -++ * this by parsing the stack map table without a full decoding -++ * (see below). -++ */ -++ } else if (FRAMES && "StackMap".equals(attrName)) { -++ if ((context.flags & SKIP_FRAMES) == 0) { -++ zip = false; -++ stackMap = u + 10; -++ stackMapSize = readInt(u + 4); -++ frameCount = readUnsignedShort(u + 8); -++ } -++ /* -++ * IMPORTANT! here we assume that the frames are ordered, as in -++ * the StackMapTable attribute, although this is not guaranteed -++ * by the attribute format. -++ */ -++ } else { -++ for (int j = 0; j < context.attrs.length; ++j) { -++ if (context.attrs[j].type.equals(attrName)) { -++ Attribute attr = context.attrs[j].read(this, u + 8, -++ readInt(u + 4), c, codeStart - 8, labels); -++ if (attr != null) { -++ attr.next = attributes; -++ attributes = attr; -++ } -++ } -++ } -++ } -++ u += 6 + readInt(u + 4); -++ } -++ u += 2; -++ -++ // generates the first (implicit) stack map frame -++ if (FRAMES && stackMap != 0) { -++ /* -++ * for the first explicit frame the offset is not offset_delta + 1 -++ * but only offset_delta; setting the implicit frame offset to -1 -++ * allow the use of the "offset_delta + 1" rule in all cases -++ */ -++ frame = context; -++ frame.offset = -1; -++ frame.mode = 0; -++ frame.localCount = 0; -++ frame.localDiff = 0; -++ frame.stackCount = 0; -++ frame.local = new Object[maxLocals]; -++ frame.stack = new Object[maxStack]; -++ if (unzip) { -++ getImplicitFrame(context); -++ } -++ /* -++ * Finds labels for UNINITIALIZED frame types. Instead of decoding -++ * each element of the stack map table, we look for 3 consecutive -++ * bytes that "look like" an UNINITIALIZED type (tag 8, offset -++ * within code bounds, NEW instruction at this offset). We may find -++ * false positives (i.e. not real UNINITIALIZED types), but this -++ * should be rare, and the only consequence will be the creation of -++ * an unneeded label. This is better than creating a label for each -++ * NEW instruction, and faster than fully decoding the whole stack -++ * map table. -++ */ -++ for (int i = stackMap; i < stackMap + stackMapSize - 2; ++i) { -++ if (b[i] == 8) { // UNINITIALIZED FRAME TYPE -++ int v = readUnsignedShort(i + 1); -++ if (v >= 0 && v < codeLength) { -++ if ((b[codeStart + v] & 0xFF) == Opcodes.NEW) { -++ readLabel(v, labels); -++ } -++ } -++ } -++ } -++ } -++ -++ // visits the instructions -++ u = codeStart; -++ while (u < codeEnd) { -++ int offset = u - codeStart; -++ -++ // visits the label and line number for this offset, if any -++ Label l = labels[offset]; -++ if (l != null) { -++ Label next = l.next; -++ l.next = null; -++ mv.visitLabel(l); -++ if ((context.flags & SKIP_DEBUG) == 0 && l.line > 0) { -++ mv.visitLineNumber(l.line, l); -++ while (next != null) { -++ mv.visitLineNumber(next.line, l); -++ next = next.next; -++ } -++ } -++ } -++ -++ // visits the frame for this offset, if any -++ while (FRAMES && frame != null -++ && (frame.offset == offset || frame.offset == -1)) { -++ // if there is a frame for this offset, makes the visitor visit -++ // it, and reads the next frame if there is one. -++ if (frame.offset != -1) { -++ if (!zip || unzip) { -++ mv.visitFrame(Opcodes.F_NEW, frame.localCount, -++ frame.local, frame.stackCount, frame.stack); -++ } else { -++ mv.visitFrame(frame.mode, frame.localDiff, frame.local, -++ frame.stackCount, frame.stack); -++ } -++ } -++ if (frameCount > 0) { -++ stackMap = readFrame(stackMap, zip, unzip, frame); -++ --frameCount; -++ } else { -++ frame = null; -++ } -++ } -++ -++ // visits the instruction at this offset -++ int opcode = b[u] & 0xFF; -++ switch (ClassWriter.TYPE[opcode]) { -++ case ClassWriter.NOARG_INSN: -++ mv.visitInsn(opcode); -++ u += 1; -++ break; -++ case ClassWriter.IMPLVAR_INSN: -++ if (opcode > Opcodes.ISTORE) { -++ opcode -= 59; // ISTORE_0 -++ mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), -++ opcode & 0x3); -++ } else { -++ opcode -= 26; // ILOAD_0 -++ mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3); -++ } -++ u += 1; -++ break; -++ case ClassWriter.LABEL_INSN: -++ mv.visitJumpInsn(opcode, labels[offset + readShort(u + 1)]); -++ u += 3; -++ break; -++ case ClassWriter.LABELW_INSN: -++ mv.visitJumpInsn(opcode - 33, labels[offset + readInt(u + 1)]); -++ u += 5; -++ break; -++ case ClassWriter.WIDE_INSN: -++ opcode = b[u + 1] & 0xFF; -++ if (opcode == Opcodes.IINC) { -++ mv.visitIincInsn(readUnsignedShort(u + 2), readShort(u + 4)); -++ u += 6; -++ } else { -++ mv.visitVarInsn(opcode, readUnsignedShort(u + 2)); -++ u += 4; -++ } -++ break; -++ case ClassWriter.TABL_INSN: { -++ // skips 0 to 3 padding bytes -++ u = u + 4 - (offset & 3); -++ // reads instruction -++ int label = offset + readInt(u); -++ int min = readInt(u + 4); -++ int max = readInt(u + 8); -++ Label[] table = new Label[max - min + 1]; -++ u += 12; -++ for (int i = 0; i < table.length; ++i) { -++ table[i] = labels[offset + readInt(u)]; -++ u += 4; -++ } -++ mv.visitTableSwitchInsn(min, max, labels[label], table); -++ break; -++ } -++ case ClassWriter.LOOK_INSN: { -++ // skips 0 to 3 padding bytes -++ u = u + 4 - (offset & 3); -++ // reads instruction -++ int label = offset + readInt(u); -++ int len = readInt(u + 4); -++ int[] keys = new int[len]; -++ Label[] values = new Label[len]; -++ u += 8; -++ for (int i = 0; i < len; ++i) { -++ keys[i] = readInt(u); -++ values[i] = labels[offset + readInt(u + 4)]; -++ u += 8; -++ } -++ mv.visitLookupSwitchInsn(labels[label], keys, values); -++ break; -++ } -++ case ClassWriter.VAR_INSN: -++ mv.visitVarInsn(opcode, b[u + 1] & 0xFF); -++ u += 2; -++ break; -++ case ClassWriter.SBYTE_INSN: -++ mv.visitIntInsn(opcode, b[u + 1]); -++ u += 2; -++ break; -++ case ClassWriter.SHORT_INSN: -++ mv.visitIntInsn(opcode, readShort(u + 1)); -++ u += 3; -++ break; -++ case ClassWriter.LDC_INSN: -++ mv.visitLdcInsn(readConst(b[u + 1] & 0xFF, c)); -++ u += 2; -++ break; -++ case ClassWriter.LDCW_INSN: -++ mv.visitLdcInsn(readConst(readUnsignedShort(u + 1), c)); -++ u += 3; -++ break; -++ case ClassWriter.FIELDORMETH_INSN: -++ case ClassWriter.ITFMETH_INSN: { -++ int cpIndex = items[readUnsignedShort(u + 1)]; -++ boolean itf = b[cpIndex - 1] == ClassWriter.IMETH; -++ String iowner = readClass(cpIndex, c); -++ cpIndex = items[readUnsignedShort(cpIndex + 2)]; -++ String iname = readUTF8(cpIndex, c); -++ String idesc = readUTF8(cpIndex + 2, c); -++ if (opcode < Opcodes.INVOKEVIRTUAL) { -++ mv.visitFieldInsn(opcode, iowner, iname, idesc); -++ } else { -++ mv.visitMethodInsn(opcode, iowner, iname, idesc, itf); -++ } -++ if (opcode == Opcodes.INVOKEINTERFACE) { -++ u += 5; -++ } else { -++ u += 3; -++ } -++ break; -++ } -++ case ClassWriter.INDYMETH_INSN: { -++ int cpIndex = items[readUnsignedShort(u + 1)]; -++ int bsmIndex = context.bootstrapMethods[readUnsignedShort(cpIndex)]; -++ Handle bsm = (Handle) readConst(readUnsignedShort(bsmIndex), c); -++ int bsmArgCount = readUnsignedShort(bsmIndex + 2); -++ Object[] bsmArgs = new Object[bsmArgCount]; -++ bsmIndex += 4; -++ for (int i = 0; i < bsmArgCount; i++) { -++ bsmArgs[i] = readConst(readUnsignedShort(bsmIndex), c); -++ bsmIndex += 2; -++ } -++ cpIndex = items[readUnsignedShort(cpIndex + 2)]; -++ String iname = readUTF8(cpIndex, c); -++ String idesc = readUTF8(cpIndex + 2, c); -++ mv.visitInvokeDynamicInsn(iname, idesc, bsm, bsmArgs); -++ u += 5; -++ break; -++ } -++ case ClassWriter.TYPE_INSN: -++ mv.visitTypeInsn(opcode, readClass(u + 1, c)); -++ u += 3; -++ break; -++ case ClassWriter.IINC_INSN: -++ mv.visitIincInsn(b[u + 1] & 0xFF, b[u + 2]); -++ u += 3; -++ break; -++ // case MANA_INSN: -++ default: -++ mv.visitMultiANewArrayInsn(readClass(u + 1, c), b[u + 3] & 0xFF); -++ u += 4; -++ break; -++ } -++ -++ // visit the instruction annotations, if any -++ while (tanns != null && tann < tanns.length && ntoff <= offset) { -++ if (ntoff == offset) { -++ int v = readAnnotationTarget(context, tanns[tann]); -++ readAnnotationValues(v + 2, c, true, -++ mv.visitInsnAnnotation(context.typeRef, -++ context.typePath, readUTF8(v, c), true)); -++ } -++ ntoff = ++tann >= tanns.length || readByte(tanns[tann]) < 0x43 ? -1 -++ : readUnsignedShort(tanns[tann] + 1); -++ } -++ while (itanns != null && itann < itanns.length && nitoff <= offset) { -++ if (nitoff == offset) { -++ int v = readAnnotationTarget(context, itanns[itann]); -++ readAnnotationValues(v + 2, c, true, -++ mv.visitInsnAnnotation(context.typeRef, -++ context.typePath, readUTF8(v, c), false)); -++ } -++ nitoff = ++itann >= itanns.length -++ || readByte(itanns[itann]) < 0x43 ? -1 -++ : readUnsignedShort(itanns[itann] + 1); -++ } -++ } -++ if (labels[codeLength] != null) { -++ mv.visitLabel(labels[codeLength]); -++ } -++ -++ // visits the local variable tables -++ if ((context.flags & SKIP_DEBUG) == 0 && varTable != 0) { -++ int[] typeTable = null; -++ if (varTypeTable != 0) { -++ u = varTypeTable + 2; -++ typeTable = new int[readUnsignedShort(varTypeTable) * 3]; -++ for (int i = typeTable.length; i > 0;) { -++ typeTable[--i] = u + 6; // signature -++ typeTable[--i] = readUnsignedShort(u + 8); // index -++ typeTable[--i] = readUnsignedShort(u); // start -++ u += 10; -++ } -++ } -++ u = varTable + 2; -++ for (int i = readUnsignedShort(varTable); i > 0; --i) { -++ int start = readUnsignedShort(u); -++ int length = readUnsignedShort(u + 2); -++ int index = readUnsignedShort(u + 8); -++ String vsignature = null; -++ if (typeTable != null) { -++ for (int j = 0; j < typeTable.length; j += 3) { -++ if (typeTable[j] == start && typeTable[j + 1] == index) { -++ vsignature = readUTF8(typeTable[j + 2], c); -++ break; -++ } -++ } -++ } -++ mv.visitLocalVariable(readUTF8(u + 4, c), readUTF8(u + 6, c), -++ vsignature, labels[start], labels[start + length], -++ index); -++ u += 10; -++ } -++ } -++ -++ // visits the local variables type annotations -++ if (tanns != null) { -++ for (int i = 0; i < tanns.length; ++i) { -++ if ((readByte(tanns[i]) >> 1) == (0x40 >> 1)) { -++ int v = readAnnotationTarget(context, tanns[i]); -++ v = readAnnotationValues(v + 2, c, true, -++ mv.visitLocalVariableAnnotation(context.typeRef, -++ context.typePath, context.start, -++ context.end, context.index, readUTF8(v, c), -++ true)); -++ } -++ } -++ } -++ if (itanns != null) { -++ for (int i = 0; i < itanns.length; ++i) { -++ if ((readByte(itanns[i]) >> 1) == (0x40 >> 1)) { -++ int v = readAnnotationTarget(context, itanns[i]); -++ v = readAnnotationValues(v + 2, c, true, -++ mv.visitLocalVariableAnnotation(context.typeRef, -++ context.typePath, context.start, -++ context.end, context.index, readUTF8(v, c), -++ false)); -++ } -++ } -++ } -++ -++ // visits the code attributes -++ while (attributes != null) { -++ Attribute attr = attributes.next; -++ attributes.next = null; -++ mv.visitAttribute(attributes); -++ attributes = attr; -++ } -++ -++ // visits the max stack and max locals values -++ mv.visitMaxs(maxStack, maxLocals); -++ } -++ -++ /** -++ * Parses a type annotation table to find the labels, and to visit the try -++ * catch block annotations. -++ * -++ * @param u -++ * the start offset of a type annotation table. -++ * @param mv -++ * the method visitor to be used to visit the try catch block -++ * annotations. -++ * @param context -++ * information about the class being parsed. -++ * @param visible -++ * if the type annotation table to parse contains runtime visible -++ * annotations. -++ * @return the start offset of each type annotation in the parsed table. -++ */ -++ private int[] readTypeAnnotations(final MethodVisitor mv, -++ final Context context, int u, boolean visible) { -++ char[] c = context.buffer; -++ int[] offsets = new int[readUnsignedShort(u)]; -++ u += 2; -++ for (int i = 0; i < offsets.length; ++i) { -++ offsets[i] = u; -++ int target = readInt(u); -++ switch (target >>> 24) { -++ case 0x00: // CLASS_TYPE_PARAMETER -++ case 0x01: // METHOD_TYPE_PARAMETER -++ case 0x16: // METHOD_FORMAL_PARAMETER -++ u += 2; -++ break; -++ case 0x13: // FIELD -++ case 0x14: // METHOD_RETURN -++ case 0x15: // METHOD_RECEIVER -++ u += 1; -++ break; -++ case 0x40: // LOCAL_VARIABLE -++ case 0x41: // RESOURCE_VARIABLE -++ for (int j = readUnsignedShort(u + 1); j > 0; --j) { -++ int start = readUnsignedShort(u + 3); -++ int length = readUnsignedShort(u + 5); -++ readLabel(start, context.labels); -++ readLabel(start + length, context.labels); -++ u += 6; -++ } -++ u += 3; -++ break; -++ case 0x47: // CAST -++ case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT -++ case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT -++ case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT -++ case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT -++ u += 4; -++ break; -++ // case 0x10: // CLASS_EXTENDS -++ // case 0x11: // CLASS_TYPE_PARAMETER_BOUND -++ // case 0x12: // METHOD_TYPE_PARAMETER_BOUND -++ // case 0x17: // THROWS -++ // case 0x42: // EXCEPTION_PARAMETER -++ // case 0x43: // INSTANCEOF -++ // case 0x44: // NEW -++ // case 0x45: // CONSTRUCTOR_REFERENCE -++ // case 0x46: // METHOD_REFERENCE -++ default: -++ u += 3; -++ break; -++ } -++ int pathLength = readByte(u); -++ if ((target >>> 24) == 0x42) { -++ TypePath path = pathLength == 0 ? null : new TypePath(b, u); -++ u += 1 + 2 * pathLength; -++ u = readAnnotationValues(u + 2, c, true, -++ mv.visitTryCatchAnnotation(target, path, -++ readUTF8(u, c), visible)); -++ } else { -++ u = readAnnotationValues(u + 3 + 2 * pathLength, c, true, null); -++ } -++ } -++ return offsets; -++ } -++ -++ /** -++ * Parses the header of a type annotation to extract its target_type and -++ * target_path (the result is stored in the given context), and returns the -++ * start offset of the rest of the type_annotation structure (i.e. the -++ * offset to the type_index field, which is followed by -++ * num_element_value_pairs and then the name,value pairs). -++ * -++ * @param context -++ * information about the class being parsed. This is where the -++ * extracted target_type and target_path must be stored. -++ * @param u -++ * the start offset of a type_annotation structure. -++ * @return the start offset of the rest of the type_annotation structure. -++ */ -++ private int readAnnotationTarget(final Context context, int u) { -++ int target = readInt(u); -++ switch (target >>> 24) { -++ case 0x00: // CLASS_TYPE_PARAMETER -++ case 0x01: // METHOD_TYPE_PARAMETER -++ case 0x16: // METHOD_FORMAL_PARAMETER -++ target &= 0xFFFF0000; -++ u += 2; -++ break; -++ case 0x13: // FIELD -++ case 0x14: // METHOD_RETURN -++ case 0x15: // METHOD_RECEIVER -++ target &= 0xFF000000; -++ u += 1; -++ break; -++ case 0x40: // LOCAL_VARIABLE -++ case 0x41: { // RESOURCE_VARIABLE -++ target &= 0xFF000000; -++ int n = readUnsignedShort(u + 1); -++ context.start = new Label[n]; -++ context.end = new Label[n]; -++ context.index = new int[n]; -++ u += 3; -++ for (int i = 0; i < n; ++i) { -++ int start = readUnsignedShort(u); -++ int length = readUnsignedShort(u + 2); -++ context.start[i] = readLabel(start, context.labels); -++ context.end[i] = readLabel(start + length, context.labels); -++ context.index[i] = readUnsignedShort(u + 4); -++ u += 6; -++ } -++ break; -++ } -++ case 0x47: // CAST -++ case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT -++ case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT -++ case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT -++ case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT -++ target &= 0xFF0000FF; -++ u += 4; -++ break; -++ // case 0x10: // CLASS_EXTENDS -++ // case 0x11: // CLASS_TYPE_PARAMETER_BOUND -++ // case 0x12: // METHOD_TYPE_PARAMETER_BOUND -++ // case 0x17: // THROWS -++ // case 0x42: // EXCEPTION_PARAMETER -++ // case 0x43: // INSTANCEOF -++ // case 0x44: // NEW -++ // case 0x45: // CONSTRUCTOR_REFERENCE -++ // case 0x46: // METHOD_REFERENCE -++ default: -++ target &= (target >>> 24) < 0x43 ? 0xFFFFFF00 : 0xFF000000; -++ u += 3; -++ break; -++ } -++ int pathLength = readByte(u); -++ context.typeRef = target; -++ context.typePath = pathLength == 0 ? null : new TypePath(b, u); -++ return u + 1 + 2 * pathLength; -++ } -++ -++ /** -++ * Reads parameter annotations and makes the given visitor visit them. -++ * -++ * @param mv -++ * the visitor that must visit the annotations. -++ * @param context -++ * information about the class being parsed. -++ * @param v -++ * start offset in {@link #b b} of the annotations to be read. -++ * @param visible -++ * <tt>true</tt> if the annotations to be read are visible at -++ * runtime. -++ */ -++ private void readParameterAnnotations(final MethodVisitor mv, -++ final Context context, int v, final boolean visible) { -++ int i; -++ int n = b[v++] & 0xFF; -++ // workaround for a bug in javac (javac compiler generates a parameter -++ // annotation array whose size is equal to the number of parameters in -++ // the Java source file, while it should generate an array whose size is -++ // equal to the number of parameters in the method descriptor - which -++ // includes the synthetic parameters added by the compiler). This work- -++ // around supposes that the synthetic parameters are the first ones. -++ int synthetics = Type.getArgumentTypes(context.desc).length - n; -++ AnnotationVisitor av; -++ for (i = 0; i < synthetics; ++i) { -++ // virtual annotation to detect synthetic parameters in MethodWriter -++ av = mv.visitParameterAnnotation(i, "Ljava/lang/Synthetic;", false); -++ if (av != null) { -++ av.visitEnd(); -++ } -++ } -++ char[] c = context.buffer; -++ for (; i < n + synthetics; ++i) { -++ int j = readUnsignedShort(v); -++ v += 2; -++ for (; j > 0; --j) { -++ av = mv.visitParameterAnnotation(i, readUTF8(v, c), visible); -++ v = readAnnotationValues(v + 2, c, true, av); -++ } -++ } -++ } -++ -++ /** -++ * Reads the values of an annotation and makes the given visitor visit them. -++ * -++ * @param v -++ * the start offset in {@link #b b} of the values to be read -++ * (including the unsigned short that gives the number of -++ * values). -++ * @param buf -++ * buffer to be used to call {@link #readUTF8 readUTF8}, -++ * {@link #readClass(int,char[]) readClass} or {@link #readConst -++ * readConst}. -++ * @param named -++ * if the annotation values are named or not. -++ * @param av -++ * the visitor that must visit the values. -++ * @return the end offset of the annotation values. -++ */ -++ private int readAnnotationValues(int v, final char[] buf, -++ final boolean named, final AnnotationVisitor av) { -++ int i = readUnsignedShort(v); -++ v += 2; -++ if (named) { -++ for (; i > 0; --i) { -++ v = readAnnotationValue(v + 2, buf, readUTF8(v, buf), av); -++ } -++ } else { -++ for (; i > 0; --i) { -++ v = readAnnotationValue(v, buf, null, av); -++ } -++ } -++ if (av != null) { -++ av.visitEnd(); -++ } -++ return v; -++ } -++ -++ /** -++ * Reads a value of an annotation and makes the given visitor visit it. -++ * -++ * @param v -++ * the start offset in {@link #b b} of the value to be read -++ * (<i>not including the value name constant pool index</i>). -++ * @param buf -++ * buffer to be used to call {@link #readUTF8 readUTF8}, -++ * {@link #readClass(int,char[]) readClass} or {@link #readConst -++ * readConst}. -++ * @param name -++ * the name of the value to be read. -++ * @param av -++ * the visitor that must visit the value. -++ * @return the end offset of the annotation value. -++ */ -++ private int readAnnotationValue(int v, final char[] buf, final String name, -++ final AnnotationVisitor av) { -++ int i; -++ if (av == null) { -++ switch (b[v] & 0xFF) { -++ case 'e': // enum_const_value -++ return v + 5; -++ case '@': // annotation_value -++ return readAnnotationValues(v + 3, buf, true, null); -++ case '[': // array_value -++ return readAnnotationValues(v + 1, buf, false, null); -++ default: -++ return v + 3; -++ } -++ } -++ switch (b[v++] & 0xFF) { -++ case 'I': // pointer to CONSTANT_Integer -++ case 'J': // pointer to CONSTANT_Long -++ case 'F': // pointer to CONSTANT_Float -++ case 'D': // pointer to CONSTANT_Double -++ av.visit(name, readConst(readUnsignedShort(v), buf)); -++ v += 2; -++ break; -++ case 'B': // pointer to CONSTANT_Byte -++ av.visit(name, (byte) readInt(items[readUnsignedShort(v)])); -++ v += 2; -++ break; -++ case 'Z': // pointer to CONSTANT_Boolean -++ av.visit(name, -++ readInt(items[readUnsignedShort(v)]) == 0 ? Boolean.FALSE -++ : Boolean.TRUE); -++ v += 2; -++ break; -++ case 'S': // pointer to CONSTANT_Short -++ av.visit(name, (short) readInt(items[readUnsignedShort(v)])); -++ v += 2; -++ break; -++ case 'C': // pointer to CONSTANT_Char -++ av.visit(name, (char) readInt(items[readUnsignedShort(v)])); -++ v += 2; -++ break; -++ case 's': // pointer to CONSTANT_Utf8 -++ av.visit(name, readUTF8(v, buf)); -++ v += 2; -++ break; -++ case 'e': // enum_const_value -++ av.visitEnum(name, readUTF8(v, buf), readUTF8(v + 2, buf)); -++ v += 4; -++ break; -++ case 'c': // class_info -++ av.visit(name, Type.getType(readUTF8(v, buf))); -++ v += 2; -++ break; -++ case '@': // annotation_value -++ v = readAnnotationValues(v + 2, buf, true, -++ av.visitAnnotation(name, readUTF8(v, buf))); -++ break; -++ case '[': // array_value -++ int size = readUnsignedShort(v); -++ v += 2; -++ if (size == 0) { -++ return readAnnotationValues(v - 2, buf, false, -++ av.visitArray(name)); -++ } -++ switch (this.b[v++] & 0xFF) { -++ case 'B': -++ byte[] bv = new byte[size]; -++ for (i = 0; i < size; i++) { -++ bv[i] = (byte) readInt(items[readUnsignedShort(v)]); -++ v += 3; -++ } -++ av.visit(name, bv); -++ --v; -++ break; -++ case 'Z': -++ boolean[] zv = new boolean[size]; -++ for (i = 0; i < size; i++) { -++ zv[i] = readInt(items[readUnsignedShort(v)]) != 0; -++ v += 3; -++ } -++ av.visit(name, zv); -++ --v; -++ break; -++ case 'S': -++ short[] sv = new short[size]; -++ for (i = 0; i < size; i++) { -++ sv[i] = (short) readInt(items[readUnsignedShort(v)]); -++ v += 3; -++ } -++ av.visit(name, sv); -++ --v; -++ break; -++ case 'C': -++ char[] cv = new char[size]; -++ for (i = 0; i < size; i++) { -++ cv[i] = (char) readInt(items[readUnsignedShort(v)]); -++ v += 3; -++ } -++ av.visit(name, cv); -++ --v; -++ break; -++ case 'I': -++ int[] iv = new int[size]; -++ for (i = 0; i < size; i++) { -++ iv[i] = readInt(items[readUnsignedShort(v)]); -++ v += 3; -++ } -++ av.visit(name, iv); -++ --v; -++ break; -++ case 'J': -++ long[] lv = new long[size]; -++ for (i = 0; i < size; i++) { -++ lv[i] = readLong(items[readUnsignedShort(v)]); -++ v += 3; -++ } -++ av.visit(name, lv); -++ --v; -++ break; -++ case 'F': -++ float[] fv = new float[size]; -++ for (i = 0; i < size; i++) { -++ fv[i] = Float -++ .intBitsToFloat(readInt(items[readUnsignedShort(v)])); -++ v += 3; -++ } -++ av.visit(name, fv); -++ --v; -++ break; -++ case 'D': -++ double[] dv = new double[size]; -++ for (i = 0; i < size; i++) { -++ dv[i] = Double -++ .longBitsToDouble(readLong(items[readUnsignedShort(v)])); -++ v += 3; -++ } -++ av.visit(name, dv); -++ --v; -++ break; -++ default: -++ v = readAnnotationValues(v - 3, buf, false, av.visitArray(name)); -++ } -++ } -++ return v; -++ } -++ -++ /** -++ * Computes the implicit frame of the method currently being parsed (as -++ * defined in the given {@link Context}) and stores it in the given context. -++ * -++ * @param frame -++ * information about the class being parsed. -++ */ -++ private void getImplicitFrame(final Context frame) { -++ String desc = frame.desc; -++ Object[] locals = frame.local; -++ int local = 0; -++ if ((frame.access & Opcodes.ACC_STATIC) == 0) { -++ if ("<init>".equals(frame.name)) { -++ locals[local++] = Opcodes.UNINITIALIZED_THIS; -++ } else { -++ locals[local++] = readClass(header + 2, frame.buffer); -++ } -++ } -++ int i = 1; -++ loop: while (true) { -++ int j = i; -++ switch (desc.charAt(i++)) { -++ case 'Z': -++ case 'C': -++ case 'B': -++ case 'S': -++ case 'I': -++ locals[local++] = Opcodes.INTEGER; -++ break; -++ case 'F': -++ locals[local++] = Opcodes.FLOAT; -++ break; -++ case 'J': -++ locals[local++] = Opcodes.LONG; -++ break; -++ case 'D': -++ locals[local++] = Opcodes.DOUBLE; -++ break; -++ case '[': -++ while (desc.charAt(i) == '[') { -++ ++i; -++ } -++ if (desc.charAt(i) == 'L') { -++ ++i; -++ while (desc.charAt(i) != ';') { -++ ++i; -++ } -++ } -++ locals[local++] = desc.substring(j, ++i); -++ break; -++ case 'L': -++ while (desc.charAt(i) != ';') { -++ ++i; -++ } -++ locals[local++] = desc.substring(j + 1, i++); -++ break; -++ default: -++ break loop; -++ } -++ } -++ frame.localCount = local; -++ } -++ -++ /** -++ * Reads a stack map frame and stores the result in the given -++ * {@link Context} object. -++ * -++ * @param stackMap -++ * the start offset of a stack map frame in the class file. -++ * @param zip -++ * if the stack map frame at stackMap is compressed or not. -++ * @param unzip -++ * if the stack map frame must be uncompressed. -++ * @param frame -++ * where the parsed stack map frame must be stored. -++ * @return the offset of the first byte following the parsed frame. -++ */ -++ private int readFrame(int stackMap, boolean zip, boolean unzip, -++ Context frame) { -++ char[] c = frame.buffer; -++ Label[] labels = frame.labels; -++ int tag; -++ int delta; -++ if (zip) { -++ tag = b[stackMap++] & 0xFF; -++ } else { -++ tag = MethodWriter.FULL_FRAME; -++ frame.offset = -1; -++ } -++ frame.localDiff = 0; -++ if (tag < MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME) { -++ delta = tag; -++ frame.mode = Opcodes.F_SAME; -++ frame.stackCount = 0; -++ } else if (tag < MethodWriter.RESERVED) { -++ delta = tag - MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME; -++ stackMap = readFrameType(frame.stack, 0, stackMap, c, labels); -++ frame.mode = Opcodes.F_SAME1; -++ frame.stackCount = 1; -++ } else { -++ delta = readUnsignedShort(stackMap); -++ stackMap += 2; -++ if (tag == MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { -++ stackMap = readFrameType(frame.stack, 0, stackMap, c, labels); -++ frame.mode = Opcodes.F_SAME1; -++ frame.stackCount = 1; -++ } else if (tag >= MethodWriter.CHOP_FRAME -++ && tag < MethodWriter.SAME_FRAME_EXTENDED) { -++ frame.mode = Opcodes.F_CHOP; -++ frame.localDiff = MethodWriter.SAME_FRAME_EXTENDED - tag; -++ frame.localCount -= frame.localDiff; -++ frame.stackCount = 0; -++ } else if (tag == MethodWriter.SAME_FRAME_EXTENDED) { -++ frame.mode = Opcodes.F_SAME; -++ frame.stackCount = 0; -++ } else if (tag < MethodWriter.FULL_FRAME) { -++ int local = unzip ? frame.localCount : 0; -++ for (int i = tag - MethodWriter.SAME_FRAME_EXTENDED; i > 0; i--) { -++ stackMap = readFrameType(frame.local, local++, stackMap, c, -++ labels); -++ } -++ frame.mode = Opcodes.F_APPEND; -++ frame.localDiff = tag - MethodWriter.SAME_FRAME_EXTENDED; -++ frame.localCount += frame.localDiff; -++ frame.stackCount = 0; -++ } else { // if (tag == FULL_FRAME) { -++ frame.mode = Opcodes.F_FULL; -++ int n = readUnsignedShort(stackMap); -++ stackMap += 2; -++ frame.localDiff = n; -++ frame.localCount = n; -++ for (int local = 0; n > 0; n--) { -++ stackMap = readFrameType(frame.local, local++, stackMap, c, -++ labels); -++ } -++ n = readUnsignedShort(stackMap); -++ stackMap += 2; -++ frame.stackCount = n; -++ for (int stack = 0; n > 0; n--) { -++ stackMap = readFrameType(frame.stack, stack++, stackMap, c, -++ labels); -++ } -++ } -++ } -++ frame.offset += delta + 1; -++ readLabel(frame.offset, labels); -++ return stackMap; -++ } -++ -++ /** -++ * Reads a stack map frame type and stores it at the given index in the -++ * given array. -++ * -++ * @param frame -++ * the array where the parsed type must be stored. -++ * @param index -++ * the index in 'frame' where the parsed type must be stored. -++ * @param v -++ * the start offset of the stack map frame type to read. -++ * @param buf -++ * a buffer to read strings. -++ * @param labels -++ * the labels of the method currently being parsed, indexed by -++ * their offset. If the parsed type is an Uninitialized type, a -++ * new label for the corresponding NEW instruction is stored in -++ * this array if it does not already exist. -++ * @return the offset of the first byte after the parsed type. -++ */ -++ private int readFrameType(final Object[] frame, final int index, int v, -++ final char[] buf, final Label[] labels) { -++ int type = b[v++] & 0xFF; -++ switch (type) { -++ case 0: -++ frame[index] = Opcodes.TOP; -++ break; -++ case 1: -++ frame[index] = Opcodes.INTEGER; -++ break; -++ case 2: -++ frame[index] = Opcodes.FLOAT; -++ break; -++ case 3: -++ frame[index] = Opcodes.DOUBLE; -++ break; -++ case 4: -++ frame[index] = Opcodes.LONG; -++ break; -++ case 5: -++ frame[index] = Opcodes.NULL; -++ break; -++ case 6: -++ frame[index] = Opcodes.UNINITIALIZED_THIS; -++ break; -++ case 7: // Object -++ frame[index] = readClass(v, buf); -++ v += 2; -++ break; -++ default: // Uninitialized -++ frame[index] = readLabel(readUnsignedShort(v), labels); -++ v += 2; -++ } -++ return v; -++ } -++ -++ /** -++ * Returns the label corresponding to the given offset. The default -++ * implementation of this method creates a label for the given offset if it -++ * has not been already created. -++ * -++ * @param offset -++ * a bytecode offset in a method. -++ * @param labels -++ * the already created labels, indexed by their offset. If a -++ * label already exists for offset this method must not create a -++ * new one. Otherwise it must store the new label in this array. -++ * @return a non null Label, which must be equal to labels[offset]. -++ */ -++ protected Label readLabel(int offset, Label[] labels) { -++ if (labels[offset] == null) { -++ labels[offset] = new Label(); -++ } -++ return labels[offset]; -++ } -++ -++ /** -++ * Returns the start index of the attribute_info structure of this class. -++ * -++ * @return the start index of the attribute_info structure of this class. -++ */ -++ private int getAttributes() { -++ // skips the header -++ int u = header + 8 + readUnsignedShort(header + 6) * 2; -++ // skips fields and methods -++ for (int i = readUnsignedShort(u); i > 0; --i) { -++ for (int j = readUnsignedShort(u + 8); j > 0; --j) { -++ u += 6 + readInt(u + 12); -++ } -++ u += 8; -++ } -++ u += 2; -++ for (int i = readUnsignedShort(u); i > 0; --i) { -++ for (int j = readUnsignedShort(u + 8); j > 0; --j) { -++ u += 6 + readInt(u + 12); -++ } -++ u += 8; -++ } -++ // the attribute_info structure starts just after the methods -++ return u + 2; -++ } -++ -++ /** -++ * Reads an attribute in {@link #b b}. -++ * -++ * @param attrs -++ * prototypes of the attributes that must be parsed during the -++ * visit of the class. Any attribute whose type is not equal to -++ * the type of one the prototypes is ignored (i.e. an empty -++ * {@link Attribute} instance is returned). -++ * @param type -++ * the type of the attribute. -++ * @param off -++ * index of the first byte of the attribute's content in -++ * {@link #b b}. The 6 attribute header bytes, containing the -++ * type and the length of the attribute, are not taken into -++ * account here (they have already been read). -++ * @param len -++ * the length of the attribute's content. -++ * @param buf -++ * buffer to be used to call {@link #readUTF8 readUTF8}, -++ * {@link #readClass(int,char[]) readClass} or {@link #readConst -++ * readConst}. -++ * @param codeOff -++ * index of the first byte of code's attribute content in -++ * {@link #b b}, or -1 if the attribute to be read is not a code -++ * attribute. The 6 attribute header bytes, containing the type -++ * and the length of the attribute, are not taken into account -++ * here. -++ * @param labels -++ * the labels of the method's code, or <tt>null</tt> if the -++ * attribute to be read is not a code attribute. -++ * @return the attribute that has been read, or <tt>null</tt> to skip this -++ * attribute. -++ */ -++ private Attribute readAttribute(final Attribute[] attrs, final String type, -++ final int off, final int len, final char[] buf, final int codeOff, -++ final Label[] labels) { -++ for (int i = 0; i < attrs.length; ++i) { -++ if (attrs[i].type.equals(type)) { -++ return attrs[i].read(this, off, len, buf, codeOff, labels); -++ } -++ } -++ return new Attribute(type).read(this, off, len, null, -1, null); -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Utility methods: low level parsing -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Returns the number of constant pool items in {@link #b b}. -++ * -++ * @return the number of constant pool items in {@link #b b}. -++ */ -++ public int getItemCount() { -++ return items.length; -++ } -++ -++ /** -++ * Returns the start index of the constant pool item in {@link #b b}, plus -++ * one. <i>This method is intended for {@link Attribute} sub classes, and is -++ * normally not needed by class generators or adapters.</i> -++ * -++ * @param item -++ * the index a constant pool item. -++ * @return the start index of the constant pool item in {@link #b b}, plus -++ * one. -++ */ -++ public int getItem(final int item) { -++ return items[item]; -++ } -++ -++ /** -++ * Returns the maximum length of the strings contained in the constant pool -++ * of the class. -++ * -++ * @return the maximum length of the strings contained in the constant pool -++ * of the class. -++ */ -++ public int getMaxStringLength() { -++ return maxStringLength; -++ } -++ -++ /** -++ * Reads a byte value in {@link #b b}. <i>This method is intended for -++ * {@link Attribute} sub classes, and is normally not needed by class -++ * generators or adapters.</i> -++ * -++ * @param index -++ * the start index of the value to be read in {@link #b b}. -++ * @return the read value. -++ */ -++ public int readByte(final int index) { -++ return b[index] & 0xFF; -++ } -++ -++ /** -++ * Reads an unsigned short value in {@link #b b}. <i>This method is intended -++ * for {@link Attribute} sub classes, and is normally not needed by class -++ * generators or adapters.</i> -++ * -++ * @param index -++ * the start index of the value to be read in {@link #b b}. -++ * @return the read value. -++ */ -++ public int readUnsignedShort(final int index) { -++ byte[] b = this.b; -++ return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF); -++ } -++ -++ /** -++ * Reads a signed short value in {@link #b b}. <i>This method is intended -++ * for {@link Attribute} sub classes, and is normally not needed by class -++ * generators or adapters.</i> -++ * -++ * @param index -++ * the start index of the value to be read in {@link #b b}. -++ * @return the read value. -++ */ -++ public short readShort(final int index) { -++ byte[] b = this.b; -++ return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF)); -++ } -++ -++ /** -++ * Reads a signed int value in {@link #b b}. <i>This method is intended for -++ * {@link Attribute} sub classes, and is normally not needed by class -++ * generators or adapters.</i> -++ * -++ * @param index -++ * the start index of the value to be read in {@link #b b}. -++ * @return the read value. -++ */ -++ public int readInt(final int index) { -++ byte[] b = this.b; -++ return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16) -++ | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF); -++ } -++ -++ /** -++ * Reads a signed long value in {@link #b b}. <i>This method is intended for -++ * {@link Attribute} sub classes, and is normally not needed by class -++ * generators or adapters.</i> -++ * -++ * @param index -++ * the start index of the value to be read in {@link #b b}. -++ * @return the read value. -++ */ -++ public long readLong(final int index) { -++ long l1 = readInt(index); -++ long l0 = readInt(index + 4) & 0xFFFFFFFFL; -++ return (l1 << 32) | l0; -++ } -++ -++ /** -++ * Reads an UTF8 string constant pool item in {@link #b b}. <i>This method -++ * is intended for {@link Attribute} sub classes, and is normally not needed -++ * by class generators or adapters.</i> -++ * -++ * @param index -++ * the start index of an unsigned short value in {@link #b b}, -++ * whose value is the index of an UTF8 constant pool item. -++ * @param buf -++ * buffer to be used to read the item. This buffer must be -++ * sufficiently large. It is not automatically resized. -++ * @return the String corresponding to the specified UTF8 item. -++ */ -++ public String readUTF8(int index, final char[] buf) { -++ int item = readUnsignedShort(index); -++ if (index == 0 || item == 0) { -++ return null; -++ } -++ String s = strings[item]; -++ if (s != null) { -++ return s; -++ } -++ index = items[item]; -++ return strings[item] = readUTF(index + 2, readUnsignedShort(index), buf); -++ } -++ -++ /** -++ * Reads UTF8 string in {@link #b b}. -++ * -++ * @param index -++ * start offset of the UTF8 string to be read. -++ * @param utfLen -++ * length of the UTF8 string to be read. -++ * @param buf -++ * buffer to be used to read the string. This buffer must be -++ * sufficiently large. It is not automatically resized. -++ * @return the String corresponding to the specified UTF8 string. -++ */ -++ private String readUTF(int index, final int utfLen, final char[] buf) { -++ int endIndex = index + utfLen; -++ byte[] b = this.b; -++ int strLen = 0; -++ int c; -++ int st = 0; -++ char cc = 0; -++ while (index < endIndex) { -++ c = b[index++]; -++ switch (st) { -++ case 0: -++ c = c & 0xFF; -++ if (c < 0x80) { // 0xxxxxxx -++ buf[strLen++] = (char) c; -++ } else if (c < 0xE0 && c > 0xBF) { // 110x xxxx 10xx xxxx -++ cc = (char) (c & 0x1F); -++ st = 1; -++ } else { // 1110 xxxx 10xx xxxx 10xx xxxx -++ cc = (char) (c & 0x0F); -++ st = 2; -++ } -++ break; -++ -++ case 1: // byte 2 of 2-byte char or byte 3 of 3-byte char -++ buf[strLen++] = (char) ((cc << 6) | (c & 0x3F)); -++ st = 0; -++ break; -++ -++ case 2: // byte 2 of 3-byte char -++ cc = (char) ((cc << 6) | (c & 0x3F)); -++ st = 1; -++ break; -++ } -++ } -++ return new String(buf, 0, strLen); -++ } -++ -++ /** -++ * Reads a class constant pool item in {@link #b b}. <i>This method is -++ * intended for {@link Attribute} sub classes, and is normally not needed by -++ * class generators or adapters.</i> -++ * -++ * @param index -++ * the start index of an unsigned short value in {@link #b b}, -++ * whose value is the index of a class constant pool item. -++ * @param buf -++ * buffer to be used to read the item. This buffer must be -++ * sufficiently large. It is not automatically resized. -++ * @return the String corresponding to the specified class item. -++ */ -++ public String readClass(final int index, final char[] buf) { -++ // computes the start index of the CONSTANT_Class item in b -++ // and reads the CONSTANT_Utf8 item designated by -++ // the first two bytes of this CONSTANT_Class item -++ return readUTF8(items[readUnsignedShort(index)], buf); -++ } -++ -++ /** -++ * Reads a numeric or string constant pool item in {@link #b b}. <i>This -++ * method is intended for {@link Attribute} sub classes, and is normally not -++ * needed by class generators or adapters.</i> -++ * -++ * @param item -++ * the index of a constant pool item. -++ * @param buf -++ * buffer to be used to read the item. This buffer must be -++ * sufficiently large. It is not automatically resized. -++ * @return the {@link Integer}, {@link Float}, {@link Long}, {@link Double}, -++ * {@link String}, {@link Type} or {@link Handle} corresponding to -++ * the given constant pool item. -++ */ -++ public Object readConst(final int item, final char[] buf) { -++ int index = items[item]; -++ switch (b[index - 1]) { -++ case ClassWriter.INT: -++ return readInt(index); -++ case ClassWriter.FLOAT: -++ return Float.intBitsToFloat(readInt(index)); -++ case ClassWriter.LONG: -++ return readLong(index); -++ case ClassWriter.DOUBLE: -++ return Double.longBitsToDouble(readLong(index)); -++ case ClassWriter.CLASS: -++ return Type.getObjectType(readUTF8(index, buf)); -++ case ClassWriter.STR: -++ return readUTF8(index, buf); -++ case ClassWriter.MTYPE: -++ return Type.getMethodType(readUTF8(index, buf)); -++ default: // case ClassWriter.HANDLE_BASE + [1..9]: -++ int tag = readByte(index); -++ int[] items = this.items; -++ int cpIndex = items[readUnsignedShort(index + 1)]; -++ String owner = readClass(cpIndex, buf); -++ cpIndex = items[readUnsignedShort(cpIndex + 2)]; -++ String name = readUTF8(cpIndex, buf); -++ String desc = readUTF8(cpIndex + 2, buf); -++ return new Handle(tag, owner, name, desc); -++ } -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/ClassVisitor.java b/contrib/asm/src/org/objectweb/asm/ClassVisitor.java -+new file mode 100644 -+index 0000000..107ada0 -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/ClassVisitor.java -+@@ -0,0 +1,320 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * A visitor to visit a Java class. The methods of this class must be called in -++ * the following order: <tt>visit</tt> [ <tt>visitSource</tt> ] [ -++ * <tt>visitOuterClass</tt> ] ( <tt>visitAnnotation</tt> | -++ * <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* ( -++ * <tt>visitInnerClass</tt> | <tt>visitField</tt> | <tt>visitMethod</tt> )* -++ * <tt>visitEnd</tt>. -++ * -++ * @author Eric Bruneton -++ */ -++public abstract class ClassVisitor { -++ -++ /** -++ * The ASM API version implemented by this visitor. The value of this field -++ * must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -++ */ -++ protected final int api; -++ -++ /** -++ * The class visitor to which this visitor must delegate method calls. May -++ * be null. -++ */ -++ protected ClassVisitor cv; -++ -++ /** -++ * Constructs a new {@link ClassVisitor}. -++ * -++ * @param api -++ * the ASM API version implemented by this visitor. Must be one -++ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -++ */ -++ public ClassVisitor(final int api) { -++ this(api, null); -++ } -++ -++ /** -++ * Constructs a new {@link ClassVisitor}. -++ * -++ * @param api -++ * the ASM API version implemented by this visitor. Must be one -++ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -++ * @param cv -++ * the class visitor to which this visitor must delegate method -++ * calls. May be null. -++ */ -++ public ClassVisitor(final int api, final ClassVisitor cv) { -++ if (api != Opcodes.ASM4 && api != Opcodes.ASM5) { -++ throw new IllegalArgumentException(); -++ } -++ this.api = api; -++ this.cv = cv; -++ } -++ -++ /** -++ * Visits the header of the class. -++ * -++ * @param version -++ * the class version. -++ * @param access -++ * the class's access flags (see {@link Opcodes}). This parameter -++ * also indicates if the class is deprecated. -++ * @param name -++ * the internal name of the class (see -++ * {@link Type#getInternalName() getInternalName}). -++ * @param signature -++ * the signature of this class. May be <tt>null</tt> if the class -++ * is not a generic one, and does not extend or implement generic -++ * classes or interfaces. -++ * @param superName -++ * the internal of name of the super class (see -++ * {@link Type#getInternalName() getInternalName}). For -++ * interfaces, the super class is {@link Object}. May be -++ * <tt>null</tt>, but only for the {@link Object} class. -++ * @param interfaces -++ * the internal names of the class's interfaces (see -++ * {@link Type#getInternalName() getInternalName}). May be -++ * <tt>null</tt>. -++ */ -++ public void visit(int version, int access, String name, String signature, -++ String superName, String[] interfaces) { -++ if (cv != null) { -++ cv.visit(version, access, name, signature, superName, interfaces); -++ } -++ } -++ -++ /** -++ * Visits the source of the class. -++ * -++ * @param source -++ * the name of the source file from which the class was compiled. -++ * May be <tt>null</tt>. -++ * @param debug -++ * additional debug information to compute the correspondance -++ * between source and compiled elements of the class. May be -++ * <tt>null</tt>. -++ */ -++ public void visitSource(String source, String debug) { -++ if (cv != null) { -++ cv.visitSource(source, debug); -++ } -++ } -++ -++ /** -++ * Visits the enclosing class of the class. This method must be called only -++ * if the class has an enclosing class. -++ * -++ * @param owner -++ * internal name of the enclosing class of the class. -++ * @param name -++ * the name of the method that contains the class, or -++ * <tt>null</tt> if the class is not enclosed in a method of its -++ * enclosing class. -++ * @param desc -++ * the descriptor of the method that contains the class, or -++ * <tt>null</tt> if the class is not enclosed in a method of its -++ * enclosing class. -++ */ -++ public void visitOuterClass(String owner, String name, String desc) { -++ if (cv != null) { -++ cv.visitOuterClass(owner, name, desc); -++ } -++ } -++ -++ /** -++ * Visits an annotation of the class. -++ * -++ * @param desc -++ * the class descriptor of the annotation class. -++ * @param visible -++ * <tt>true</tt> if the annotation is visible at runtime. -++ * @return a visitor to visit the annotation values, or <tt>null</tt> if -++ * this visitor is not interested in visiting this annotation. -++ */ -++ public AnnotationVisitor visitAnnotation(String desc, boolean visible) { -++ if (cv != null) { -++ return cv.visitAnnotation(desc, visible); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits an annotation on a type in the class signature. -++ * -++ * @param typeRef -++ * a reference to the annotated type. The sort of this type -++ * reference must be {@link TypeReference#CLASS_TYPE_PARAMETER -++ * CLASS_TYPE_PARAMETER}, -++ * {@link TypeReference#CLASS_TYPE_PARAMETER_BOUND -++ * CLASS_TYPE_PARAMETER_BOUND} or -++ * {@link TypeReference#CLASS_EXTENDS CLASS_EXTENDS}. See -++ * {@link TypeReference}. -++ * @param typePath -++ * the path to the annotated type argument, wildcard bound, array -++ * element type, or static inner type within 'typeRef'. May be -++ * <tt>null</tt> if the annotation targets 'typeRef' as a whole. -++ * @param desc -++ * the class descriptor of the annotation class. -++ * @param visible -++ * <tt>true</tt> if the annotation is visible at runtime. -++ * @return a visitor to visit the annotation values, or <tt>null</tt> if -++ * this visitor is not interested in visiting this annotation. -++ */ -++ public AnnotationVisitor visitTypeAnnotation(int typeRef, -++ TypePath typePath, String desc, boolean visible) { -++ if (api < Opcodes.ASM5) { -++ throw new RuntimeException(); -++ } -++ if (cv != null) { -++ return cv.visitTypeAnnotation(typeRef, typePath, desc, visible); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits a non standard attribute of the class. -++ * -++ * @param attr -++ * an attribute. -++ */ -++ public void visitAttribute(Attribute attr) { -++ if (cv != null) { -++ cv.visitAttribute(attr); -++ } -++ } -++ -++ /** -++ * Visits information about an inner class. This inner class is not -++ * necessarily a member of the class being visited. -++ * -++ * @param name -++ * the internal name of an inner class (see -++ * {@link Type#getInternalName() getInternalName}). -++ * @param outerName -++ * the internal name of the class to which the inner class -++ * belongs (see {@link Type#getInternalName() getInternalName}). -++ * May be <tt>null</tt> for not member classes. -++ * @param innerName -++ * the (simple) name of the inner class inside its enclosing -++ * class. May be <tt>null</tt> for anonymous inner classes. -++ * @param access -++ * the access flags of the inner class as originally declared in -++ * the enclosing class. -++ */ -++ public void visitInnerClass(String name, String outerName, -++ String innerName, int access) { -++ if (cv != null) { -++ cv.visitInnerClass(name, outerName, innerName, access); -++ } -++ } -++ -++ /** -++ * Visits a field of the class. -++ * -++ * @param access -++ * the field's access flags (see {@link Opcodes}). This parameter -++ * also indicates if the field is synthetic and/or deprecated. -++ * @param name -++ * the field's name. -++ * @param desc -++ * the field's descriptor (see {@link Type Type}). -++ * @param signature -++ * the field's signature. May be <tt>null</tt> if the field's -++ * type does not use generic types. -++ * @param value -++ * the field's initial value. This parameter, which may be -++ * <tt>null</tt> if the field does not have an initial value, -++ * must be an {@link Integer}, a {@link Float}, a {@link Long}, a -++ * {@link Double} or a {@link String} (for <tt>int</tt>, -++ * <tt>float</tt>, <tt>long</tt> or <tt>String</tt> fields -++ * respectively). <i>This parameter is only used for static -++ * fields</i>. Its value is ignored for non static fields, which -++ * must be initialized through bytecode instructions in -++ * constructors or methods. -++ * @return a visitor to visit field annotations and attributes, or -++ * <tt>null</tt> if this class visitor is not interested in visiting -++ * these annotations and attributes. -++ */ -++ public FieldVisitor visitField(int access, String name, String desc, -++ String signature, Object value) { -++ if (cv != null) { -++ return cv.visitField(access, name, desc, signature, value); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits a method of the class. This method <i>must</i> return a new -++ * {@link MethodVisitor} instance (or <tt>null</tt>) each time it is called, -++ * i.e., it should not return a previously returned visitor. -++ * -++ * @param access -++ * the method's access flags (see {@link Opcodes}). This -++ * parameter also indicates if the method is synthetic and/or -++ * deprecated. -++ * @param name -++ * the method's name. -++ * @param desc -++ * the method's descriptor (see {@link Type Type}). -++ * @param signature -++ * the method's signature. May be <tt>null</tt> if the method -++ * parameters, return type and exceptions do not use generic -++ * types. -++ * @param exceptions -++ * the internal names of the method's exception classes (see -++ * {@link Type#getInternalName() getInternalName}). May be -++ * <tt>null</tt>. -++ * @return an object to visit the byte code of the method, or <tt>null</tt> -++ * if this class visitor is not interested in visiting the code of -++ * this method. -++ */ -++ public MethodVisitor visitMethod(int access, String name, String desc, -++ String signature, String[] exceptions) { -++ if (cv != null) { -++ return cv.visitMethod(access, name, desc, signature, exceptions); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits the end of the class. This method, which is the last one to be -++ * called, is used to inform the visitor that all the fields and methods of -++ * the class have been visited. -++ */ -++ public void visitEnd() { -++ if (cv != null) { -++ cv.visitEnd(); -++ } -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/ClassWriter.java b/contrib/asm/src/org/objectweb/asm/ClassWriter.java -+new file mode 100644 -+index 0000000..63e1d7e -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/ClassWriter.java -+@@ -0,0 +1,1776 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * A {@link ClassVisitor} that generates classes in bytecode form. More -++ * precisely this visitor generates a byte array conforming to the Java class -++ * file format. It can be used alone, to generate a Java class "from scratch", -++ * or with one or more {@link ClassReader ClassReader} and adapter class visitor -++ * to generate a modified class from one or more existing Java classes. -++ * -++ * @author Eric Bruneton -++ */ -++public class ClassWriter extends ClassVisitor { -++ -++ /** -++ * Flag to automatically compute the maximum stack size and the maximum -++ * number of local variables of methods. If this flag is set, then the -++ * arguments of the {@link MethodVisitor#visitMaxs visitMaxs} method of the -++ * {@link MethodVisitor} returned by the {@link #visitMethod visitMethod} -++ * method will be ignored, and computed automatically from the signature and -++ * the bytecode of each method. -++ * -++ * @see #ClassWriter(int) -++ */ -++ public static final int COMPUTE_MAXS = 1; -++ -++ /** -++ * Flag to automatically compute the stack map frames of methods from -++ * scratch. If this flag is set, then the calls to the -++ * {@link MethodVisitor#visitFrame} method are ignored, and the stack map -++ * frames are recomputed from the methods bytecode. The arguments of the -++ * {@link MethodVisitor#visitMaxs visitMaxs} method are also ignored and -++ * recomputed from the bytecode. In other words, computeFrames implies -++ * computeMaxs. -++ * -++ * @see #ClassWriter(int) -++ */ -++ public static final int COMPUTE_FRAMES = 2; -++ -++ /** -++ * Pseudo access flag to distinguish between the synthetic attribute and the -++ * synthetic access flag. -++ */ -++ static final int ACC_SYNTHETIC_ATTRIBUTE = 0x40000; -++ -++ /** -++ * Factor to convert from ACC_SYNTHETIC_ATTRIBUTE to Opcode.ACC_SYNTHETIC. -++ */ -++ static final int TO_ACC_SYNTHETIC = ACC_SYNTHETIC_ATTRIBUTE -++ / Opcodes.ACC_SYNTHETIC; -++ -++ /** -++ * The type of instructions without any argument. -++ */ -++ static final int NOARG_INSN = 0; -++ -++ /** -++ * The type of instructions with an signed byte argument. -++ */ -++ static final int SBYTE_INSN = 1; -++ -++ /** -++ * The type of instructions with an signed short argument. -++ */ -++ static final int SHORT_INSN = 2; -++ -++ /** -++ * The type of instructions with a local variable index argument. -++ */ -++ static final int VAR_INSN = 3; -++ -++ /** -++ * The type of instructions with an implicit local variable index argument. -++ */ -++ static final int IMPLVAR_INSN = 4; -++ -++ /** -++ * The type of instructions with a type descriptor argument. -++ */ -++ static final int TYPE_INSN = 5; -++ -++ /** -++ * The type of field and method invocations instructions. -++ */ -++ static final int FIELDORMETH_INSN = 6; -++ -++ /** -++ * The type of the INVOKEINTERFACE/INVOKEDYNAMIC instruction. -++ */ -++ static final int ITFMETH_INSN = 7; -++ -++ /** -++ * The type of the INVOKEDYNAMIC instruction. -++ */ -++ static final int INDYMETH_INSN = 8; -++ -++ /** -++ * The type of instructions with a 2 bytes bytecode offset label. -++ */ -++ static final int LABEL_INSN = 9; -++ -++ /** -++ * The type of instructions with a 4 bytes bytecode offset label. -++ */ -++ static final int LABELW_INSN = 10; -++ -++ /** -++ * The type of the LDC instruction. -++ */ -++ static final int LDC_INSN = 11; -++ -++ /** -++ * The type of the LDC_W and LDC2_W instructions. -++ */ -++ static final int LDCW_INSN = 12; -++ -++ /** -++ * The type of the IINC instruction. -++ */ -++ static final int IINC_INSN = 13; -++ -++ /** -++ * The type of the TABLESWITCH instruction. -++ */ -++ static final int TABL_INSN = 14; -++ -++ /** -++ * The type of the LOOKUPSWITCH instruction. -++ */ -++ static final int LOOK_INSN = 15; -++ -++ /** -++ * The type of the MULTIANEWARRAY instruction. -++ */ -++ static final int MANA_INSN = 16; -++ -++ /** -++ * The type of the WIDE instruction. -++ */ -++ static final int WIDE_INSN = 17; -++ -++ /** -++ * The instruction types of all JVM opcodes. -++ */ -++ static final byte[] TYPE; -++ -++ /** -++ * The type of CONSTANT_Class constant pool items. -++ */ -++ static final int CLASS = 7; -++ -++ /** -++ * The type of CONSTANT_Fieldref constant pool items. -++ */ -++ static final int FIELD = 9; -++ -++ /** -++ * The type of CONSTANT_Methodref constant pool items. -++ */ -++ static final int METH = 10; -++ -++ /** -++ * The type of CONSTANT_InterfaceMethodref constant pool items. -++ */ -++ static final int IMETH = 11; -++ -++ /** -++ * The type of CONSTANT_String constant pool items. -++ */ -++ static final int STR = 8; -++ -++ /** -++ * The type of CONSTANT_Integer constant pool items. -++ */ -++ static final int INT = 3; -++ -++ /** -++ * The type of CONSTANT_Float constant pool items. -++ */ -++ static final int FLOAT = 4; -++ -++ /** -++ * The type of CONSTANT_Long constant pool items. -++ */ -++ static final int LONG = 5; -++ -++ /** -++ * The type of CONSTANT_Double constant pool items. -++ */ -++ static final int DOUBLE = 6; -++ -++ /** -++ * The type of CONSTANT_NameAndType constant pool items. -++ */ -++ static final int NAME_TYPE = 12; -++ -++ /** -++ * The type of CONSTANT_Utf8 constant pool items. -++ */ -++ static final int UTF8 = 1; -++ -++ /** -++ * The type of CONSTANT_MethodType constant pool items. -++ */ -++ static final int MTYPE = 16; -++ -++ /** -++ * The type of CONSTANT_MethodHandle constant pool items. -++ */ -++ static final int HANDLE = 15; -++ -++ /** -++ * The type of CONSTANT_InvokeDynamic constant pool items. -++ */ -++ static final int INDY = 18; -++ -++ /** -++ * The base value for all CONSTANT_MethodHandle constant pool items. -++ * Internally, ASM store the 9 variations of CONSTANT_MethodHandle into 9 -++ * different items. -++ */ -++ static final int HANDLE_BASE = 20; -++ -++ /** -++ * Normal type Item stored in the ClassWriter {@link ClassWriter#typeTable}, -++ * instead of the constant pool, in order to avoid clashes with normal -++ * constant pool items in the ClassWriter constant pool's hash table. -++ */ -++ static final int TYPE_NORMAL = 30; -++ -++ /** -++ * Uninitialized type Item stored in the ClassWriter -++ * {@link ClassWriter#typeTable}, instead of the constant pool, in order to -++ * avoid clashes with normal constant pool items in the ClassWriter constant -++ * pool's hash table. -++ */ -++ static final int TYPE_UNINIT = 31; -++ -++ /** -++ * Merged type Item stored in the ClassWriter {@link ClassWriter#typeTable}, -++ * instead of the constant pool, in order to avoid clashes with normal -++ * constant pool items in the ClassWriter constant pool's hash table. -++ */ -++ static final int TYPE_MERGED = 32; -++ -++ /** -++ * The type of BootstrapMethods items. These items are stored in a special -++ * class attribute named BootstrapMethods and not in the constant pool. -++ */ -++ static final int BSM = 33; -++ -++ /** -++ * The class reader from which this class writer was constructed, if any. -++ */ -++ ClassReader cr; -++ -++ /** -++ * Minor and major version numbers of the class to be generated. -++ */ -++ int version; -++ -++ /** -++ * Index of the next item to be added in the constant pool. -++ */ -++ int index; -++ -++ /** -++ * The constant pool of this class. -++ */ -++ final ByteVector pool; -++ -++ /** -++ * The constant pool's hash table data. -++ */ -++ Item[] items; -++ -++ /** -++ * The threshold of the constant pool's hash table. -++ */ -++ int threshold; -++ -++ /** -++ * A reusable key used to look for items in the {@link #items} hash table. -++ */ -++ final Item key; -++ -++ /** -++ * A reusable key used to look for items in the {@link #items} hash table. -++ */ -++ final Item key2; -++ -++ /** -++ * A reusable key used to look for items in the {@link #items} hash table. -++ */ -++ final Item key3; -++ -++ /** -++ * A reusable key used to look for items in the {@link #items} hash table. -++ */ -++ final Item key4; -++ -++ /** -++ * A type table used to temporarily store internal names that will not -++ * necessarily be stored in the constant pool. This type table is used by -++ * the control flow and data flow analysis algorithm used to compute stack -++ * map frames from scratch. This array associates to each index <tt>i</tt> -++ * the Item whose index is <tt>i</tt>. All Item objects stored in this array -++ * are also stored in the {@link #items} hash table. These two arrays allow -++ * to retrieve an Item from its index or, conversely, to get the index of an -++ * Item from its value. Each Item stores an internal name in its -++ * {@link Item#strVal1} field. -++ */ -++ Item[] typeTable; -++ -++ /** -++ * Number of elements in the {@link #typeTable} array. -++ */ -++ private short typeCount; -++ -++ /** -++ * The access flags of this class. -++ */ -++ private int access; -++ -++ /** -++ * The constant pool item that contains the internal name of this class. -++ */ -++ private int name; -++ -++ /** -++ * The internal name of this class. -++ */ -++ String thisName; -++ -++ /** -++ * The constant pool item that contains the signature of this class. -++ */ -++ private int signature; -++ -++ /** -++ * The constant pool item that contains the internal name of the super class -++ * of this class. -++ */ -++ private int superName; -++ -++ /** -++ * Number of interfaces implemented or extended by this class or interface. -++ */ -++ private int interfaceCount; -++ -++ /** -++ * The interfaces implemented or extended by this class or interface. More -++ * precisely, this array contains the indexes of the constant pool items -++ * that contain the internal names of these interfaces. -++ */ -++ private int[] interfaces; -++ -++ /** -++ * The index of the constant pool item that contains the name of the source -++ * file from which this class was compiled. -++ */ -++ private int sourceFile; -++ -++ /** -++ * The SourceDebug attribute of this class. -++ */ -++ private ByteVector sourceDebug; -++ -++ /** -++ * The constant pool item that contains the name of the enclosing class of -++ * this class. -++ */ -++ private int enclosingMethodOwner; -++ -++ /** -++ * The constant pool item that contains the name and descriptor of the -++ * enclosing method of this class. -++ */ -++ private int enclosingMethod; -++ -++ /** -++ * The runtime visible annotations of this class. -++ */ -++ private AnnotationWriter anns; -++ -++ /** -++ * The runtime invisible annotations of this class. -++ */ -++ private AnnotationWriter ianns; -++ -++ /** -++ * The runtime visible type annotations of this class. -++ */ -++ private AnnotationWriter tanns; -++ -++ /** -++ * The runtime invisible type annotations of this class. -++ */ -++ private AnnotationWriter itanns; -++ -++ /** -++ * The non standard attributes of this class. -++ */ -++ private Attribute attrs; -++ -++ /** -++ * The number of entries in the InnerClasses attribute. -++ */ -++ private int innerClassesCount; -++ -++ /** -++ * The InnerClasses attribute. -++ */ -++ private ByteVector innerClasses; -++ -++ /** -++ * The number of entries in the BootstrapMethods attribute. -++ */ -++ int bootstrapMethodsCount; -++ -++ /** -++ * The BootstrapMethods attribute. -++ */ -++ ByteVector bootstrapMethods; -++ -++ /** -++ * The fields of this class. These fields are stored in a linked list of -++ * {@link FieldWriter} objects, linked to each other by their -++ * {@link FieldWriter#fv} field. This field stores the first element of this -++ * list. -++ */ -++ FieldWriter firstField; -++ -++ /** -++ * The fields of this class. These fields are stored in a linked list of -++ * {@link FieldWriter} objects, linked to each other by their -++ * {@link FieldWriter#fv} field. This field stores the last element of this -++ * list. -++ */ -++ FieldWriter lastField; -++ -++ /** -++ * The methods of this class. These methods are stored in a linked list of -++ * {@link MethodWriter} objects, linked to each other by their -++ * {@link MethodWriter#mv} field. This field stores the first element of -++ * this list. -++ */ -++ MethodWriter firstMethod; -++ -++ /** -++ * The methods of this class. These methods are stored in a linked list of -++ * {@link MethodWriter} objects, linked to each other by their -++ * {@link MethodWriter#mv} field. This field stores the last element of this -++ * list. -++ */ -++ MethodWriter lastMethod; -++ -++ /** -++ * <tt>true</tt> if the maximum stack size and number of local variables -++ * must be automatically computed. -++ */ -++ private boolean computeMaxs; -++ -++ /** -++ * <tt>true</tt> if the stack map frames must be recomputed from scratch. -++ */ -++ private boolean computeFrames; -++ -++ /** -++ * <tt>true</tt> if the stack map tables of this class are invalid. The -++ * {@link MethodWriter#resizeInstructions} method cannot transform existing -++ * stack map tables, and so produces potentially invalid classes when it is -++ * executed. In this case the class is reread and rewritten with the -++ * {@link #COMPUTE_FRAMES} option (the resizeInstructions method can resize -++ * stack map tables when this option is used). -++ */ -++ boolean invalidFrames; -++ -++ // ------------------------------------------------------------------------ -++ // Static initializer -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Computes the instruction types of JVM opcodes. -++ */ -++ static { -++ int i; -++ byte[] b = new byte[220]; -++ String s = "AAAAAAAAAAAAAAAABCLMMDDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAADD" -++ + "DDDEEEEEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" -++ + "AAAAAAAAAAAAAAAAANAAAAAAAAAAAAAAAAAAAAJJJJJJJJJJJJJJJJDOPAA" -++ + "AAAAGGGGGGGHIFBFAAFFAARQJJKKJJJJJJJJJJJJJJJJJJ"; -++ for (i = 0; i < b.length; ++i) { -++ b[i] = (byte) (s.charAt(i) - 'A'); -++ } -++ TYPE = b; -++ -++ // code to generate the above string -++ // -++ // // SBYTE_INSN instructions -++ // b[Constants.NEWARRAY] = SBYTE_INSN; -++ // b[Constants.BIPUSH] = SBYTE_INSN; -++ // -++ // // SHORT_INSN instructions -++ // b[Constants.SIPUSH] = SHORT_INSN; -++ // -++ // // (IMPL)VAR_INSN instructions -++ // b[Constants.RET] = VAR_INSN; -++ // for (i = Constants.ILOAD; i <= Constants.ALOAD; ++i) { -++ // b[i] = VAR_INSN; -++ // } -++ // for (i = Constants.ISTORE; i <= Constants.ASTORE; ++i) { -++ // b[i] = VAR_INSN; -++ // } -++ // for (i = 26; i <= 45; ++i) { // ILOAD_0 to ALOAD_3 -++ // b[i] = IMPLVAR_INSN; -++ // } -++ // for (i = 59; i <= 78; ++i) { // ISTORE_0 to ASTORE_3 -++ // b[i] = IMPLVAR_INSN; -++ // } -++ // -++ // // TYPE_INSN instructions -++ // b[Constants.NEW] = TYPE_INSN; -++ // b[Constants.ANEWARRAY] = TYPE_INSN; -++ // b[Constants.CHECKCAST] = TYPE_INSN; -++ // b[Constants.INSTANCEOF] = TYPE_INSN; -++ // -++ // // (Set)FIELDORMETH_INSN instructions -++ // for (i = Constants.GETSTATIC; i <= Constants.INVOKESTATIC; ++i) { -++ // b[i] = FIELDORMETH_INSN; -++ // } -++ // b[Constants.INVOKEINTERFACE] = ITFMETH_INSN; -++ // b[Constants.INVOKEDYNAMIC] = INDYMETH_INSN; -++ // -++ // // LABEL(W)_INSN instructions -++ // for (i = Constants.IFEQ; i <= Constants.JSR; ++i) { -++ // b[i] = LABEL_INSN; -++ // } -++ // b[Constants.IFNULL] = LABEL_INSN; -++ // b[Constants.IFNONNULL] = LABEL_INSN; -++ // b[200] = LABELW_INSN; // GOTO_W -++ // b[201] = LABELW_INSN; // JSR_W -++ // // temporary opcodes used internally by ASM - see Label and -++ // MethodWriter -++ // for (i = 202; i < 220; ++i) { -++ // b[i] = LABEL_INSN; -++ // } -++ // -++ // // LDC(_W) instructions -++ // b[Constants.LDC] = LDC_INSN; -++ // b[19] = LDCW_INSN; // LDC_W -++ // b[20] = LDCW_INSN; // LDC2_W -++ // -++ // // special instructions -++ // b[Constants.IINC] = IINC_INSN; -++ // b[Constants.TABLESWITCH] = TABL_INSN; -++ // b[Constants.LOOKUPSWITCH] = LOOK_INSN; -++ // b[Constants.MULTIANEWARRAY] = MANA_INSN; -++ // b[196] = WIDE_INSN; // WIDE -++ // -++ // for (i = 0; i < b.length; ++i) { -++ // System.err.print((char)('A' + b[i])); -++ // } -++ // System.err.println(); -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Constructor -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Constructs a new {@link ClassWriter} object. -++ * -++ * @param flags -++ * option flags that can be used to modify the default behavior -++ * of this class. See {@link #COMPUTE_MAXS}, -++ * {@link #COMPUTE_FRAMES}. -++ */ -++ public ClassWriter(final int flags) { -++ super(Opcodes.ASM5); -++ index = 1; -++ pool = new ByteVector(); -++ items = new Item[256]; -++ threshold = (int) (0.75d * items.length); -++ key = new Item(); -++ key2 = new Item(); -++ key3 = new Item(); -++ key4 = new Item(); -++ this.computeMaxs = (flags & COMPUTE_MAXS) != 0; -++ this.computeFrames = (flags & COMPUTE_FRAMES) != 0; -++ } -++ -++ /** -++ * Constructs a new {@link ClassWriter} object and enables optimizations for -++ * "mostly add" bytecode transformations. These optimizations are the -++ * following: -++ * -++ * <ul> -++ * <li>The constant pool from the original class is copied as is in the new -++ * class, which saves time. New constant pool entries will be added at the -++ * end if necessary, but unused constant pool entries <i>won't be -++ * removed</i>.</li> -++ * <li>Methods that are not transformed are copied as is in the new class, -++ * directly from the original class bytecode (i.e. without emitting visit -++ * events for all the method instructions), which saves a <i>lot</i> of -++ * time. Untransformed methods are detected by the fact that the -++ * {@link ClassReader} receives {@link MethodVisitor} objects that come from -++ * a {@link ClassWriter} (and not from any other {@link ClassVisitor} -++ * instance).</li> -++ * </ul> -++ * -++ * @param classReader -++ * the {@link ClassReader} used to read the original class. It -++ * will be used to copy the entire constant pool from the -++ * original class and also to copy other fragments of original -++ * bytecode where applicable. -++ * @param flags -++ * option flags that can be used to modify the default behavior -++ * of this class. <i>These option flags do not affect methods -++ * that are copied as is in the new class. This means that the -++ * maximum stack size nor the stack frames will be computed for -++ * these methods</i>. See {@link #COMPUTE_MAXS}, -++ * {@link #COMPUTE_FRAMES}. -++ */ -++ public ClassWriter(final ClassReader classReader, final int flags) { -++ this(flags); -++ classReader.copyPool(this); -++ this.cr = classReader; -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Implementation of the ClassVisitor abstract class -++ // ------------------------------------------------------------------------ -++ -++ @Override -++ public final void visit(final int version, final int access, -++ final String name, final String signature, final String superName, -++ final String[] interfaces) { -++ this.version = version; -++ this.access = access; -++ this.name = newClass(name); -++ thisName = name; -++ if (ClassReader.SIGNATURES && signature != null) { -++ this.signature = newUTF8(signature); -++ } -++ this.superName = superName == null ? 0 : newClass(superName); -++ if (interfaces != null && interfaces.length > 0) { -++ interfaceCount = interfaces.length; -++ this.interfaces = new int[interfaceCount]; -++ for (int i = 0; i < interfaceCount; ++i) { -++ this.interfaces[i] = newClass(interfaces[i]); -++ } -++ } -++ } -++ -++ @Override -++ public final void visitSource(final String file, final String debug) { -++ if (file != null) { -++ sourceFile = newUTF8(file); -++ } -++ if (debug != null) { -++ sourceDebug = new ByteVector().encodeUTF8(debug, 0, -++ Integer.MAX_VALUE); -++ } -++ } -++ -++ @Override -++ public final void visitOuterClass(final String owner, final String name, -++ final String desc) { -++ enclosingMethodOwner = newClass(owner); -++ if (name != null && desc != null) { -++ enclosingMethod = newNameType(name, desc); -++ } -++ } -++ -++ @Override -++ public final AnnotationVisitor visitAnnotation(final String desc, -++ final boolean visible) { -++ if (!ClassReader.ANNOTATIONS) { -++ return null; -++ } -++ ByteVector bv = new ByteVector(); -++ // write type, and reserve space for values count -++ bv.putShort(newUTF8(desc)).putShort(0); -++ AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv, 2); -++ if (visible) { -++ aw.next = anns; -++ anns = aw; -++ } else { -++ aw.next = ianns; -++ ianns = aw; -++ } -++ return aw; -++ } -++ -++ @Override -++ public final AnnotationVisitor visitTypeAnnotation(int typeRef, -++ TypePath typePath, final String desc, final boolean visible) { -++ if (!ClassReader.ANNOTATIONS) { -++ return null; -++ } -++ ByteVector bv = new ByteVector(); -++ // write target_type and target_info -++ AnnotationWriter.putTarget(typeRef, typePath, bv); -++ // write type, and reserve space for values count -++ bv.putShort(newUTF8(desc)).putShort(0); -++ AnnotationWriter aw = new AnnotationWriter(this, true, bv, bv, -++ bv.length - 2); -++ if (visible) { -++ aw.next = tanns; -++ tanns = aw; -++ } else { -++ aw.next = itanns; -++ itanns = aw; -++ } -++ return aw; -++ } -++ -++ @Override -++ public final void visitAttribute(final Attribute attr) { -++ attr.next = attrs; -++ attrs = attr; -++ } -++ -++ @Override -++ public final void visitInnerClass(final String name, -++ final String outerName, final String innerName, final int access) { -++ if (innerClasses == null) { -++ innerClasses = new ByteVector(); -++ } -++ // Sec. 4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the -++ // constant_pool table which represents a class or interface C that is -++ // not a package member must have exactly one corresponding entry in the -++ // classes array". To avoid duplicates we keep track in the intVal field -++ // of the Item of each CONSTANT_Class_info entry C whether an inner -++ // class entry has already been added for C (this field is unused for -++ // class entries, and changing its value does not change the hashcode -++ // and equality tests). If so we store the index of this inner class -++ // entry (plus one) in intVal. This hack allows duplicate detection in -++ // O(1) time. -++ Item nameItem = newClassItem(name); -++ if (nameItem.intVal == 0) { -++ ++innerClassesCount; -++ innerClasses.putShort(nameItem.index); -++ innerClasses.putShort(outerName == null ? 0 : newClass(outerName)); -++ innerClasses.putShort(innerName == null ? 0 : newUTF8(innerName)); -++ innerClasses.putShort(access); -++ nameItem.intVal = innerClassesCount; -++ } else { -++ // Compare the inner classes entry nameItem.intVal - 1 with the -++ // arguments of this method and throw an exception if there is a -++ // difference? -++ } -++ } -++ -++ @Override -++ public final FieldVisitor visitField(final int access, final String name, -++ final String desc, final String signature, final Object value) { -++ return new FieldWriter(this, access, name, desc, signature, value); -++ } -++ -++ @Override -++ public final MethodVisitor visitMethod(final int access, final String name, -++ final String desc, final String signature, final String[] exceptions) { -++ return new MethodWriter(this, access, name, desc, signature, -++ exceptions, computeMaxs, computeFrames); -++ } -++ -++ @Override -++ public final void visitEnd() { -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Other public methods -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Returns the bytecode of the class that was build with this class writer. -++ * -++ * @return the bytecode of the class that was build with this class writer. -++ */ -++ public byte[] toByteArray() { -++ if (index > 0xFFFF) { -++ throw new RuntimeException("Class file too large!"); -++ } -++ // computes the real size of the bytecode of this class -++ int size = 24 + 2 * interfaceCount; -++ int nbFields = 0; -++ FieldWriter fb = firstField; -++ while (fb != null) { -++ ++nbFields; -++ size += fb.getSize(); -++ fb = (FieldWriter) fb.fv; -++ } -++ int nbMethods = 0; -++ MethodWriter mb = firstMethod; -++ while (mb != null) { -++ ++nbMethods; -++ size += mb.getSize(); -++ mb = (MethodWriter) mb.mv; -++ } -++ int attributeCount = 0; -++ if (bootstrapMethods != null) { -++ // we put it as first attribute in order to improve a bit -++ // ClassReader.copyBootstrapMethods -++ ++attributeCount; -++ size += 8 + bootstrapMethods.length; -++ newUTF8("BootstrapMethods"); -++ } -++ if (ClassReader.SIGNATURES && signature != 0) { -++ ++attributeCount; -++ size += 8; -++ newUTF8("Signature"); -++ } -++ if (sourceFile != 0) { -++ ++attributeCount; -++ size += 8; -++ newUTF8("SourceFile"); -++ } -++ if (sourceDebug != null) { -++ ++attributeCount; -++ size += sourceDebug.length + 6; -++ newUTF8("SourceDebugExtension"); -++ } -++ if (enclosingMethodOwner != 0) { -++ ++attributeCount; -++ size += 10; -++ newUTF8("EnclosingMethod"); -++ } -++ if ((access & Opcodes.ACC_DEPRECATED) != 0) { -++ ++attributeCount; -++ size += 6; -++ newUTF8("Deprecated"); -++ } -++ if ((access & Opcodes.ACC_SYNTHETIC) != 0) { -++ if ((version & 0xFFFF) < Opcodes.V1_5 -++ || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) { -++ ++attributeCount; -++ size += 6; -++ newUTF8("Synthetic"); -++ } -++ } -++ if (innerClasses != null) { -++ ++attributeCount; -++ size += 8 + innerClasses.length; -++ newUTF8("InnerClasses"); -++ } -++ if (ClassReader.ANNOTATIONS && anns != null) { -++ ++attributeCount; -++ size += 8 + anns.getSize(); -++ newUTF8("RuntimeVisibleAnnotations"); -++ } -++ if (ClassReader.ANNOTATIONS && ianns != null) { -++ ++attributeCount; -++ size += 8 + ianns.getSize(); -++ newUTF8("RuntimeInvisibleAnnotations"); -++ } -++ if (ClassReader.ANNOTATIONS && tanns != null) { -++ ++attributeCount; -++ size += 8 + tanns.getSize(); -++ newUTF8("RuntimeVisibleTypeAnnotations"); -++ } -++ if (ClassReader.ANNOTATIONS && itanns != null) { -++ ++attributeCount; -++ size += 8 + itanns.getSize(); -++ newUTF8("RuntimeInvisibleTypeAnnotations"); -++ } -++ if (attrs != null) { -++ attributeCount += attrs.getCount(); -++ size += attrs.getSize(this, null, 0, -1, -1); -++ } -++ size += pool.length; -++ // allocates a byte vector of this size, in order to avoid unnecessary -++ // arraycopy operations in the ByteVector.enlarge() method -++ ByteVector out = new ByteVector(size); -++ out.putInt(0xCAFEBABE).putInt(version); -++ out.putShort(index).putByteArray(pool.data, 0, pool.length); -++ int mask = Opcodes.ACC_DEPRECATED | ACC_SYNTHETIC_ATTRIBUTE -++ | ((access & ACC_SYNTHETIC_ATTRIBUTE) / TO_ACC_SYNTHETIC); -++ out.putShort(access & ~mask).putShort(name).putShort(superName); -++ out.putShort(interfaceCount); -++ for (int i = 0; i < interfaceCount; ++i) { -++ out.putShort(interfaces[i]); -++ } -++ out.putShort(nbFields); -++ fb = firstField; -++ while (fb != null) { -++ fb.put(out); -++ fb = (FieldWriter) fb.fv; -++ } -++ out.putShort(nbMethods); -++ mb = firstMethod; -++ while (mb != null) { -++ mb.put(out); -++ mb = (MethodWriter) mb.mv; -++ } -++ out.putShort(attributeCount); -++ if (bootstrapMethods != null) { -++ out.putShort(newUTF8("BootstrapMethods")); -++ out.putInt(bootstrapMethods.length + 2).putShort( -++ bootstrapMethodsCount); -++ out.putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length); -++ } -++ if (ClassReader.SIGNATURES && signature != 0) { -++ out.putShort(newUTF8("Signature")).putInt(2).putShort(signature); -++ } -++ if (sourceFile != 0) { -++ out.putShort(newUTF8("SourceFile")).putInt(2).putShort(sourceFile); -++ } -++ if (sourceDebug != null) { -++ int len = sourceDebug.length; -++ out.putShort(newUTF8("SourceDebugExtension")).putInt(len); -++ out.putByteArray(sourceDebug.data, 0, len); -++ } -++ if (enclosingMethodOwner != 0) { -++ out.putShort(newUTF8("EnclosingMethod")).putInt(4); -++ out.putShort(enclosingMethodOwner).putShort(enclosingMethod); -++ } -++ if ((access & Opcodes.ACC_DEPRECATED) != 0) { -++ out.putShort(newUTF8("Deprecated")).putInt(0); -++ } -++ if ((access & Opcodes.ACC_SYNTHETIC) != 0) { -++ if ((version & 0xFFFF) < Opcodes.V1_5 -++ || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) { -++ out.putShort(newUTF8("Synthetic")).putInt(0); -++ } -++ } -++ if (innerClasses != null) { -++ out.putShort(newUTF8("InnerClasses")); -++ out.putInt(innerClasses.length + 2).putShort(innerClassesCount); -++ out.putByteArray(innerClasses.data, 0, innerClasses.length); -++ } -++ if (ClassReader.ANNOTATIONS && anns != null) { -++ out.putShort(newUTF8("RuntimeVisibleAnnotations")); -++ anns.put(out); -++ } -++ if (ClassReader.ANNOTATIONS && ianns != null) { -++ out.putShort(newUTF8("RuntimeInvisibleAnnotations")); -++ ianns.put(out); -++ } -++ if (ClassReader.ANNOTATIONS && tanns != null) { -++ out.putShort(newUTF8("RuntimeVisibleTypeAnnotations")); -++ tanns.put(out); -++ } -++ if (ClassReader.ANNOTATIONS && itanns != null) { -++ out.putShort(newUTF8("RuntimeInvisibleTypeAnnotations")); -++ itanns.put(out); -++ } -++ if (attrs != null) { -++ attrs.put(this, null, 0, -1, -1, out); -++ } -++ if (invalidFrames) { -++ anns = null; -++ ianns = null; -++ attrs = null; -++ innerClassesCount = 0; -++ innerClasses = null; -++ bootstrapMethodsCount = 0; -++ bootstrapMethods = null; -++ firstField = null; -++ lastField = null; -++ firstMethod = null; -++ lastMethod = null; -++ computeMaxs = false; -++ computeFrames = true; -++ invalidFrames = false; -++ new ClassReader(out.data).accept(this, ClassReader.SKIP_FRAMES); -++ return toByteArray(); -++ } -++ return out.data; -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Utility methods: constant pool management -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Adds a number or string constant to the constant pool of the class being -++ * build. Does nothing if the constant pool already contains a similar item. -++ * -++ * @param cst -++ * the value of the constant to be added to the constant pool. -++ * This parameter must be an {@link Integer}, a {@link Float}, a -++ * {@link Long}, a {@link Double}, a {@link String} or a -++ * {@link Type}. -++ * @return a new or already existing constant item with the given value. -++ */ -++ Item newConstItem(final Object cst) { -++ if (cst instanceof Integer) { -++ int val = ((Integer) cst).intValue(); -++ return newInteger(val); -++ } else if (cst instanceof Byte) { -++ int val = ((Byte) cst).intValue(); -++ return newInteger(val); -++ } else if (cst instanceof Character) { -++ int val = ((Character) cst).charValue(); -++ return newInteger(val); -++ } else if (cst instanceof Short) { -++ int val = ((Short) cst).intValue(); -++ return newInteger(val); -++ } else if (cst instanceof Boolean) { -++ int val = ((Boolean) cst).booleanValue() ? 1 : 0; -++ return newInteger(val); -++ } else if (cst instanceof Float) { -++ float val = ((Float) cst).floatValue(); -++ return newFloat(val); -++ } else if (cst instanceof Long) { -++ long val = ((Long) cst).longValue(); -++ return newLong(val); -++ } else if (cst instanceof Double) { -++ double val = ((Double) cst).doubleValue(); -++ return newDouble(val); -++ } else if (cst instanceof String) { -++ return newString((String) cst); -++ } else if (cst instanceof Type) { -++ Type t = (Type) cst; -++ int s = t.getSort(); -++ if (s == Type.OBJECT) { -++ return newClassItem(t.getInternalName()); -++ } else if (s == Type.METHOD) { -++ return newMethodTypeItem(t.getDescriptor()); -++ } else { // s == primitive type or array -++ return newClassItem(t.getDescriptor()); -++ } -++ } else if (cst instanceof Handle) { -++ Handle h = (Handle) cst; -++ return newHandleItem(h.tag, h.owner, h.name, h.desc); -++ } else { -++ throw new IllegalArgumentException("value " + cst); -++ } -++ } -++ -++ /** -++ * Adds a number or string constant to the constant pool of the class being -++ * build. Does nothing if the constant pool already contains a similar item. -++ * <i>This method is intended for {@link Attribute} sub classes, and is -++ * normally not needed by class generators or adapters.</i> -++ * -++ * @param cst -++ * the value of the constant to be added to the constant pool. -++ * This parameter must be an {@link Integer}, a {@link Float}, a -++ * {@link Long}, a {@link Double} or a {@link String}. -++ * @return the index of a new or already existing constant item with the -++ * given value. -++ */ -++ public int newConst(final Object cst) { -++ return newConstItem(cst).index; -++ } -++ -++ /** -++ * Adds an UTF8 string to the constant pool of the class being build. Does -++ * nothing if the constant pool already contains a similar item. <i>This -++ * method is intended for {@link Attribute} sub classes, and is normally not -++ * needed by class generators or adapters.</i> -++ * -++ * @param value -++ * the String value. -++ * @return the index of a new or already existing UTF8 item. -++ */ -++ public int newUTF8(final String value) { -++ key.set(UTF8, value, null, null); -++ Item result = get(key); -++ if (result == null) { -++ pool.putByte(UTF8).putUTF8(value); -++ result = new Item(index++, key); -++ put(result); -++ } -++ return result.index; -++ } -++ -++ /** -++ * Adds a class reference to the constant pool of the class being build. -++ * Does nothing if the constant pool already contains a similar item. -++ * <i>This method is intended for {@link Attribute} sub classes, and is -++ * normally not needed by class generators or adapters.</i> -++ * -++ * @param value -++ * the internal name of the class. -++ * @return a new or already existing class reference item. -++ */ -++ Item newClassItem(final String value) { -++ key2.set(CLASS, value, null, null); -++ Item result = get(key2); -++ if (result == null) { -++ pool.put12(CLASS, newUTF8(value)); -++ result = new Item(index++, key2); -++ put(result); -++ } -++ return result; -++ } -++ -++ /** -++ * Adds a class reference to the constant pool of the class being build. -++ * Does nothing if the constant pool already contains a similar item. -++ * <i>This method is intended for {@link Attribute} sub classes, and is -++ * normally not needed by class generators or adapters.</i> -++ * -++ * @param value -++ * the internal name of the class. -++ * @return the index of a new or already existing class reference item. -++ */ -++ public int newClass(final String value) { -++ return newClassItem(value).index; -++ } -++ -++ /** -++ * Adds a method type reference to the constant pool of the class being -++ * build. Does nothing if the constant pool already contains a similar item. -++ * <i>This method is intended for {@link Attribute} sub classes, and is -++ * normally not needed by class generators or adapters.</i> -++ * -++ * @param methodDesc -++ * method descriptor of the method type. -++ * @return a new or already existing method type reference item. -++ */ -++ Item newMethodTypeItem(final String methodDesc) { -++ key2.set(MTYPE, methodDesc, null, null); -++ Item result = get(key2); -++ if (result == null) { -++ pool.put12(MTYPE, newUTF8(methodDesc)); -++ result = new Item(index++, key2); -++ put(result); -++ } -++ return result; -++ } -++ -++ /** -++ * Adds a method type reference to the constant pool of the class being -++ * build. Does nothing if the constant pool already contains a similar item. -++ * <i>This method is intended for {@link Attribute} sub classes, and is -++ * normally not needed by class generators or adapters.</i> -++ * -++ * @param methodDesc -++ * method descriptor of the method type. -++ * @return the index of a new or already existing method type reference -++ * item. -++ */ -++ public int newMethodType(final String methodDesc) { -++ return newMethodTypeItem(methodDesc).index; -++ } -++ -++ /** -++ * Adds a handle to the constant pool of the class being build. Does nothing -++ * if the constant pool already contains a similar item. <i>This method is -++ * intended for {@link Attribute} sub classes, and is normally not needed by -++ * class generators or adapters.</i> -++ * -++ * @param tag -++ * the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, -++ * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, -++ * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, -++ * {@link Opcodes#H_INVOKESTATIC}, -++ * {@link Opcodes#H_INVOKESPECIAL}, -++ * {@link Opcodes#H_NEWINVOKESPECIAL} or -++ * {@link Opcodes#H_INVOKEINTERFACE}. -++ * @param owner -++ * the internal name of the field or method owner class. -++ * @param name -++ * the name of the field or method. -++ * @param desc -++ * the descriptor of the field or method. -++ * @return a new or an already existing method type reference item. -++ */ -++ Item newHandleItem(final int tag, final String owner, final String name, -++ final String desc) { -++ key4.set(HANDLE_BASE + tag, owner, name, desc); -++ Item result = get(key4); -++ if (result == null) { -++ if (tag <= Opcodes.H_PUTSTATIC) { -++ put112(HANDLE, tag, newField(owner, name, desc)); -++ } else { -++ put112(HANDLE, -++ tag, -++ newMethod(owner, name, desc, -++ tag == Opcodes.H_INVOKEINTERFACE)); -++ } -++ result = new Item(index++, key4); -++ put(result); -++ } -++ return result; -++ } -++ -++ /** -++ * Adds a handle to the constant pool of the class being build. Does nothing -++ * if the constant pool already contains a similar item. <i>This method is -++ * intended for {@link Attribute} sub classes, and is normally not needed by -++ * class generators or adapters.</i> -++ * -++ * @param tag -++ * the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, -++ * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, -++ * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, -++ * {@link Opcodes#H_INVOKESTATIC}, -++ * {@link Opcodes#H_INVOKESPECIAL}, -++ * {@link Opcodes#H_NEWINVOKESPECIAL} or -++ * {@link Opcodes#H_INVOKEINTERFACE}. -++ * @param owner -++ * the internal name of the field or method owner class. -++ * @param name -++ * the name of the field or method. -++ * @param desc -++ * the descriptor of the field or method. -++ * @return the index of a new or already existing method type reference -++ * item. -++ */ -++ public int newHandle(final int tag, final String owner, final String name, -++ final String desc) { -++ return newHandleItem(tag, owner, name, desc).index; -++ } -++ -++ /** -++ * Adds an invokedynamic reference to the constant pool of the class being -++ * build. Does nothing if the constant pool already contains a similar item. -++ * <i>This method is intended for {@link Attribute} sub classes, and is -++ * normally not needed by class generators or adapters.</i> -++ * -++ * @param name -++ * name of the invoked method. -++ * @param desc -++ * descriptor of the invoke method. -++ * @param bsm -++ * the bootstrap method. -++ * @param bsmArgs -++ * the bootstrap method constant arguments. -++ * -++ * @return a new or an already existing invokedynamic type reference item. -++ */ -++ Item newInvokeDynamicItem(final String name, final String desc, -++ final Handle bsm, final Object... bsmArgs) { -++ // cache for performance -++ ByteVector bootstrapMethods = this.bootstrapMethods; -++ if (bootstrapMethods == null) { -++ bootstrapMethods = this.bootstrapMethods = new ByteVector(); -++ } -++ -++ int position = bootstrapMethods.length; // record current position -++ -++ int hashCode = bsm.hashCode(); -++ bootstrapMethods.putShort(newHandle(bsm.tag, bsm.owner, bsm.name, -++ bsm.desc)); -++ -++ int argsLength = bsmArgs.length; -++ bootstrapMethods.putShort(argsLength); -++ -++ for (int i = 0; i < argsLength; i++) { -++ Object bsmArg = bsmArgs[i]; -++ hashCode ^= bsmArg.hashCode(); -++ bootstrapMethods.putShort(newConst(bsmArg)); -++ } -++ -++ byte[] data = bootstrapMethods.data; -++ int length = (1 + 1 + argsLength) << 1; // (bsm + argCount + arguments) -++ hashCode &= 0x7FFFFFFF; -++ Item result = items[hashCode % items.length]; -++ loop: while (result != null) { -++ if (result.type != BSM || result.hashCode != hashCode) { -++ result = result.next; -++ continue; -++ } -++ -++ // because the data encode the size of the argument -++ // we don't need to test if these size are equals -++ int resultPosition = result.intVal; -++ for (int p = 0; p < length; p++) { -++ if (data[position + p] != data[resultPosition + p]) { -++ result = result.next; -++ continue loop; -++ } -++ } -++ break; -++ } -++ -++ int bootstrapMethodIndex; -++ if (result != null) { -++ bootstrapMethodIndex = result.index; -++ bootstrapMethods.length = position; // revert to old position -++ } else { -++ bootstrapMethodIndex = bootstrapMethodsCount++; -++ result = new Item(bootstrapMethodIndex); -++ result.set(position, hashCode); -++ put(result); -++ } -++ -++ // now, create the InvokeDynamic constant -++ key3.set(name, desc, bootstrapMethodIndex); -++ result = get(key3); -++ if (result == null) { -++ put122(INDY, bootstrapMethodIndex, newNameType(name, desc)); -++ result = new Item(index++, key3); -++ put(result); -++ } -++ return result; -++ } -++ -++ /** -++ * Adds an invokedynamic reference to the constant pool of the class being -++ * build. Does nothing if the constant pool already contains a similar item. -++ * <i>This method is intended for {@link Attribute} sub classes, and is -++ * normally not needed by class generators or adapters.</i> -++ * -++ * @param name -++ * name of the invoked method. -++ * @param desc -++ * descriptor of the invoke method. -++ * @param bsm -++ * the bootstrap method. -++ * @param bsmArgs -++ * the bootstrap method constant arguments. -++ * -++ * @return the index of a new or already existing invokedynamic reference -++ * item. -++ */ -++ public int newInvokeDynamic(final String name, final String desc, -++ final Handle bsm, final Object... bsmArgs) { -++ return newInvokeDynamicItem(name, desc, bsm, bsmArgs).index; -++ } -++ -++ /** -++ * Adds a field reference to the constant pool of the class being build. -++ * Does nothing if the constant pool already contains a similar item. -++ * -++ * @param owner -++ * the internal name of the field's owner class. -++ * @param name -++ * the field's name. -++ * @param desc -++ * the field's descriptor. -++ * @return a new or already existing field reference item. -++ */ -++ Item newFieldItem(final String owner, final String name, final String desc) { -++ key3.set(FIELD, owner, name, desc); -++ Item result = get(key3); -++ if (result == null) { -++ put122(FIELD, newClass(owner), newNameType(name, desc)); -++ result = new Item(index++, key3); -++ put(result); -++ } -++ return result; -++ } -++ -++ /** -++ * Adds a field reference to the constant pool of the class being build. -++ * Does nothing if the constant pool already contains a similar item. -++ * <i>This method is intended for {@link Attribute} sub classes, and is -++ * normally not needed by class generators or adapters.</i> -++ * -++ * @param owner -++ * the internal name of the field's owner class. -++ * @param name -++ * the field's name. -++ * @param desc -++ * the field's descriptor. -++ * @return the index of a new or already existing field reference item. -++ */ -++ public int newField(final String owner, final String name, final String desc) { -++ return newFieldItem(owner, name, desc).index; -++ } -++ -++ /** -++ * Adds a method reference to the constant pool of the class being build. -++ * Does nothing if the constant pool already contains a similar item. -++ * -++ * @param owner -++ * the internal name of the method's owner class. -++ * @param name -++ * the method's name. -++ * @param desc -++ * the method's descriptor. -++ * @param itf -++ * <tt>true</tt> if <tt>owner</tt> is an interface. -++ * @return a new or already existing method reference item. -++ */ -++ Item newMethodItem(final String owner, final String name, -++ final String desc, final boolean itf) { -++ int type = itf ? IMETH : METH; -++ key3.set(type, owner, name, desc); -++ Item result = get(key3); -++ if (result == null) { -++ put122(type, newClass(owner), newNameType(name, desc)); -++ result = new Item(index++, key3); -++ put(result); -++ } -++ return result; -++ } -++ -++ /** -++ * Adds a method reference to the constant pool of the class being build. -++ * Does nothing if the constant pool already contains a similar item. -++ * <i>This method is intended for {@link Attribute} sub classes, and is -++ * normally not needed by class generators or adapters.</i> -++ * -++ * @param owner -++ * the internal name of the method's owner class. -++ * @param name -++ * the method's name. -++ * @param desc -++ * the method's descriptor. -++ * @param itf -++ * <tt>true</tt> if <tt>owner</tt> is an interface. -++ * @return the index of a new or already existing method reference item. -++ */ -++ public int newMethod(final String owner, final String name, -++ final String desc, final boolean itf) { -++ return newMethodItem(owner, name, desc, itf).index; -++ } -++ -++ /** -++ * Adds an integer to the constant pool of the class being build. Does -++ * nothing if the constant pool already contains a similar item. -++ * -++ * @param value -++ * the int value. -++ * @return a new or already existing int item. -++ */ -++ Item newInteger(final int value) { -++ key.set(value); -++ Item result = get(key); -++ if (result == null) { -++ pool.putByte(INT).putInt(value); -++ result = new Item(index++, key); -++ put(result); -++ } -++ return result; -++ } -++ -++ /** -++ * Adds a float to the constant pool of the class being build. Does nothing -++ * if the constant pool already contains a similar item. -++ * -++ * @param value -++ * the float value. -++ * @return a new or already existing float item. -++ */ -++ Item newFloat(final float value) { -++ key.set(value); -++ Item result = get(key); -++ if (result == null) { -++ pool.putByte(FLOAT).putInt(key.intVal); -++ result = new Item(index++, key); -++ put(result); -++ } -++ return result; -++ } -++ -++ /** -++ * Adds a long to the constant pool of the class being build. Does nothing -++ * if the constant pool already contains a similar item. -++ * -++ * @param value -++ * the long value. -++ * @return a new or already existing long item. -++ */ -++ Item newLong(final long value) { -++ key.set(value); -++ Item result = get(key); -++ if (result == null) { -++ pool.putByte(LONG).putLong(value); -++ result = new Item(index, key); -++ index += 2; -++ put(result); -++ } -++ return result; -++ } -++ -++ /** -++ * Adds a double to the constant pool of the class being build. Does nothing -++ * if the constant pool already contains a similar item. -++ * -++ * @param value -++ * the double value. -++ * @return a new or already existing double item. -++ */ -++ Item newDouble(final double value) { -++ key.set(value); -++ Item result = get(key); -++ if (result == null) { -++ pool.putByte(DOUBLE).putLong(key.longVal); -++ result = new Item(index, key); -++ index += 2; -++ put(result); -++ } -++ return result; -++ } -++ -++ /** -++ * Adds a string to the constant pool of the class being build. Does nothing -++ * if the constant pool already contains a similar item. -++ * -++ * @param value -++ * the String value. -++ * @return a new or already existing string item. -++ */ -++ private Item newString(final String value) { -++ key2.set(STR, value, null, null); -++ Item result = get(key2); -++ if (result == null) { -++ pool.put12(STR, newUTF8(value)); -++ result = new Item(index++, key2); -++ put(result); -++ } -++ return result; -++ } -++ -++ /** -++ * Adds a name and type to the constant pool of the class being build. Does -++ * nothing if the constant pool already contains a similar item. <i>This -++ * method is intended for {@link Attribute} sub classes, and is normally not -++ * needed by class generators or adapters.</i> -++ * -++ * @param name -++ * a name. -++ * @param desc -++ * a type descriptor. -++ * @return the index of a new or already existing name and type item. -++ */ -++ public int newNameType(final String name, final String desc) { -++ return newNameTypeItem(name, desc).index; -++ } -++ -++ /** -++ * Adds a name and type to the constant pool of the class being build. Does -++ * nothing if the constant pool already contains a similar item. -++ * -++ * @param name -++ * a name. -++ * @param desc -++ * a type descriptor. -++ * @return a new or already existing name and type item. -++ */ -++ Item newNameTypeItem(final String name, final String desc) { -++ key2.set(NAME_TYPE, name, desc, null); -++ Item result = get(key2); -++ if (result == null) { -++ put122(NAME_TYPE, newUTF8(name), newUTF8(desc)); -++ result = new Item(index++, key2); -++ put(result); -++ } -++ return result; -++ } -++ -++ /** -++ * Adds the given internal name to {@link #typeTable} and returns its index. -++ * Does nothing if the type table already contains this internal name. -++ * -++ * @param type -++ * the internal name to be added to the type table. -++ * @return the index of this internal name in the type table. -++ */ -++ int addType(final String type) { -++ key.set(TYPE_NORMAL, type, null, null); -++ Item result = get(key); -++ if (result == null) { -++ result = addType(key); -++ } -++ return result.index; -++ } -++ -++ /** -++ * Adds the given "uninitialized" type to {@link #typeTable} and returns its -++ * index. This method is used for UNINITIALIZED types, made of an internal -++ * name and a bytecode offset. -++ * -++ * @param type -++ * the internal name to be added to the type table. -++ * @param offset -++ * the bytecode offset of the NEW instruction that created this -++ * UNINITIALIZED type value. -++ * @return the index of this internal name in the type table. -++ */ -++ int addUninitializedType(final String type, final int offset) { -++ key.type = TYPE_UNINIT; -++ key.intVal = offset; -++ key.strVal1 = type; -++ key.hashCode = 0x7FFFFFFF & (TYPE_UNINIT + type.hashCode() + offset); -++ Item result = get(key); -++ if (result == null) { -++ result = addType(key); -++ } -++ return result.index; -++ } -++ -++ /** -++ * Adds the given Item to {@link #typeTable}. -++ * -++ * @param item -++ * the value to be added to the type table. -++ * @return the added Item, which a new Item instance with the same value as -++ * the given Item. -++ */ -++ private Item addType(final Item item) { -++ ++typeCount; -++ Item result = new Item(typeCount, key); -++ put(result); -++ if (typeTable == null) { -++ typeTable = new Item[16]; -++ } -++ if (typeCount == typeTable.length) { -++ Item[] newTable = new Item[2 * typeTable.length]; -++ System.arraycopy(typeTable, 0, newTable, 0, typeTable.length); -++ typeTable = newTable; -++ } -++ typeTable[typeCount] = result; -++ return result; -++ } -++ -++ /** -++ * Returns the index of the common super type of the two given types. This -++ * method calls {@link #getCommonSuperClass} and caches the result in the -++ * {@link #items} hash table to speedup future calls with the same -++ * parameters. -++ * -++ * @param type1 -++ * index of an internal name in {@link #typeTable}. -++ * @param type2 -++ * index of an internal name in {@link #typeTable}. -++ * @return the index of the common super type of the two given types. -++ */ -++ int getMergedType(final int type1, final int type2) { -++ key2.type = TYPE_MERGED; -++ key2.longVal = type1 | (((long) type2) << 32); -++ key2.hashCode = 0x7FFFFFFF & (TYPE_MERGED + type1 + type2); -++ Item result = get(key2); -++ if (result == null) { -++ String t = typeTable[type1].strVal1; -++ String u = typeTable[type2].strVal1; -++ key2.intVal = addType(getCommonSuperClass(t, u)); -++ result = new Item((short) 0, key2); -++ put(result); -++ } -++ return result.intVal; -++ } -++ -++ /** -++ * Returns the common super type of the two given types. The default -++ * implementation of this method <i>loads</i> the two given classes and uses -++ * the java.lang.Class methods to find the common super class. It can be -++ * overridden to compute this common super type in other ways, in particular -++ * without actually loading any class, or to take into account the class -++ * that is currently being generated by this ClassWriter, which can of -++ * course not be loaded since it is under construction. -++ * -++ * @param type1 -++ * the internal name of a class. -++ * @param type2 -++ * the internal name of another class. -++ * @return the internal name of the common super class of the two given -++ * classes. -++ */ -++ protected String getCommonSuperClass(final String type1, final String type2) { -++ Class<?> c, d; -++ ClassLoader classLoader = getClass().getClassLoader(); -++ try { -++ c = Class.forName(type1.replace('/', '.'), false, classLoader); -++ d = Class.forName(type2.replace('/', '.'), false, classLoader); -++ } catch (Exception e) { -++ throw new RuntimeException(e.toString()); -++ } -++ if (c.isAssignableFrom(d)) { -++ return type1; -++ } -++ if (d.isAssignableFrom(c)) { -++ return type2; -++ } -++ if (c.isInterface() || d.isInterface()) { -++ return "java/lang/Object"; -++ } else { -++ do { -++ c = c.getSuperclass(); -++ } while (!c.isAssignableFrom(d)); -++ return c.getName().replace('.', '/'); -++ } -++ } -++ -++ /** -++ * Returns the constant pool's hash table item which is equal to the given -++ * item. -++ * -++ * @param key -++ * a constant pool item. -++ * @return the constant pool's hash table item which is equal to the given -++ * item, or <tt>null</tt> if there is no such item. -++ */ -++ private Item get(final Item key) { -++ Item i = items[key.hashCode % items.length]; -++ while (i != null && (i.type != key.type || !key.isEqualTo(i))) { -++ i = i.next; -++ } -++ return i; -++ } -++ -++ /** -++ * Puts the given item in the constant pool's hash table. The hash table -++ * <i>must</i> not already contains this item. -++ * -++ * @param i -++ * the item to be added to the constant pool's hash table. -++ */ -++ private void put(final Item i) { -++ if (index + typeCount > threshold) { -++ int ll = items.length; -++ int nl = ll * 2 + 1; -++ Item[] newItems = new Item[nl]; -++ for (int l = ll - 1; l >= 0; --l) { -++ Item j = items[l]; -++ while (j != null) { -++ int index = j.hashCode % newItems.length; -++ Item k = j.next; -++ j.next = newItems[index]; -++ newItems[index] = j; -++ j = k; -++ } -++ } -++ items = newItems; -++ threshold = (int) (nl * 0.75); -++ } -++ int index = i.hashCode % items.length; -++ i.next = items[index]; -++ items[index] = i; -++ } -++ -++ /** -++ * Puts one byte and two shorts into the constant pool. -++ * -++ * @param b -++ * a byte. -++ * @param s1 -++ * a short. -++ * @param s2 -++ * another short. -++ */ -++ private void put122(final int b, final int s1, final int s2) { -++ pool.put12(b, s1).putShort(s2); -++ } -++ -++ /** -++ * Puts two bytes and one short into the constant pool. -++ * -++ * @param b1 -++ * a byte. -++ * @param b2 -++ * another byte. -++ * @param s -++ * a short. -++ */ -++ private void put112(final int b1, final int b2, final int s) { -++ pool.put11(b1, b2).putShort(s); -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/Context.java b/contrib/asm/src/org/objectweb/asm/Context.java -+new file mode 100644 -+index 0000000..363b34c -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/Context.java -+@@ -0,0 +1,145 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++ -++package org.objectweb.asm; -++ -++/** -++ * Information about a class being parsed in a {@link ClassReader}. -++ * -++ * @author Eric Bruneton -++ */ -++class Context { -++ -++ /** -++ * Prototypes of the attributes that must be parsed for this class. -++ */ -++ Attribute[] attrs; -++ -++ /** -++ * The {@link ClassReader} option flags for the parsing of this class. -++ */ -++ int flags; -++ -++ /** -++ * The buffer used to read strings. -++ */ -++ char[] buffer; -++ -++ /** -++ * The start index of each bootstrap method. -++ */ -++ int[] bootstrapMethods; -++ -++ /** -++ * The access flags of the method currently being parsed. -++ */ -++ int access; -++ -++ /** -++ * The name of the method currently being parsed. -++ */ -++ String name; -++ -++ /** -++ * The descriptor of the method currently being parsed. -++ */ -++ String desc; -++ -++ /** -++ * The label objects, indexed by bytecode offset, of the method currently -++ * being parsed (only bytecode offsets for which a label is needed have a -++ * non null associated Label object). -++ */ -++ Label[] labels; -++ -++ /** -++ * The target of the type annotation currently being parsed. -++ */ -++ int typeRef; -++ -++ /** -++ * The path of the type annotation currently being parsed. -++ */ -++ TypePath typePath; -++ -++ /** -++ * The offset of the latest stack map frame that has been parsed. -++ */ -++ int offset; -++ -++ /** -++ * The labels corresponding to the start of the local variable ranges in the -++ * local variable type annotation currently being parsed. -++ */ -++ Label[] start; -++ -++ /** -++ * The labels corresponding to the end of the local variable ranges in the -++ * local variable type annotation currently being parsed. -++ */ -++ Label[] end; -++ -++ /** -++ * The local variable indices for each local variable range in the local -++ * variable type annotation currently being parsed. -++ */ -++ int[] index; -++ -++ /** -++ * The encoding of the latest stack map frame that has been parsed. -++ */ -++ int mode; -++ -++ /** -++ * The number of locals in the latest stack map frame that has been parsed. -++ */ -++ int localCount; -++ -++ /** -++ * The number locals in the latest stack map frame that has been parsed, -++ * minus the number of locals in the previous frame. -++ */ -++ int localDiff; -++ -++ /** -++ * The local values of the latest stack map frame that has been parsed. -++ */ -++ Object[] local; -++ -++ /** -++ * The stack size of the latest stack map frame that has been parsed. -++ */ -++ int stackCount; -++ -++ /** -++ * The stack values of the latest stack map frame that has been parsed. -++ */ -++ Object[] stack; -++} -+\ No newline at end of file -+diff --git a/contrib/asm/src/org/objectweb/asm/Edge.java b/contrib/asm/src/org/objectweb/asm/Edge.java -+new file mode 100644 -+index 0000000..4e87cba -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/Edge.java -+@@ -0,0 +1,75 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * An edge in the control flow graph of a method body. See {@link Label Label}. -++ * -++ * @author Eric Bruneton -++ */ -++class Edge { -++ -++ /** -++ * Denotes a normal control flow graph edge. -++ */ -++ static final int NORMAL = 0; -++ -++ /** -++ * Denotes a control flow graph edge corresponding to an exception handler. -++ * More precisely any {@link Edge} whose {@link #info} is strictly positive -++ * corresponds to an exception handler. The actual value of {@link #info} is -++ * the index, in the {@link ClassWriter} type table, of the exception that -++ * is catched. -++ */ -++ static final int EXCEPTION = 0x7FFFFFFF; -++ -++ /** -++ * Information about this control flow graph edge. If -++ * {@link ClassWriter#COMPUTE_MAXS} is used this field is the (relative) -++ * stack size in the basic block from which this edge originates. This size -++ * is equal to the stack size at the "jump" instruction to which this edge -++ * corresponds, relatively to the stack size at the beginning of the -++ * originating basic block. If {@link ClassWriter#COMPUTE_FRAMES} is used, -++ * this field is the kind of this control flow graph edge (i.e. NORMAL or -++ * EXCEPTION). -++ */ -++ int info; -++ -++ /** -++ * The successor block of the basic block from which this edge originates. -++ */ -++ Label successor; -++ -++ /** -++ * The next edge in the list of successors of the originating basic block. -++ * See {@link Label#successors successors}. -++ */ -++ Edge next; -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/FieldVisitor.java b/contrib/asm/src/org/objectweb/asm/FieldVisitor.java -+new file mode 100644 -+index 0000000..2372e4c -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/FieldVisitor.java -+@@ -0,0 +1,150 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * A visitor to visit a Java field. The methods of this class must be called in -++ * the following order: ( <tt>visitAnnotation</tt> | -++ * <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* <tt>visitEnd</tt>. -++ * -++ * @author Eric Bruneton -++ */ -++public abstract class FieldVisitor { -++ -++ /** -++ * The ASM API version implemented by this visitor. The value of this field -++ * must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -++ */ -++ protected final int api; -++ -++ /** -++ * The field visitor to which this visitor must delegate method calls. May -++ * be null. -++ */ -++ protected FieldVisitor fv; -++ -++ /** -++ * Constructs a new {@link FieldVisitor}. -++ * -++ * @param api -++ * the ASM API version implemented by this visitor. Must be one -++ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -++ */ -++ public FieldVisitor(final int api) { -++ this(api, null); -++ } -++ -++ /** -++ * Constructs a new {@link FieldVisitor}. -++ * -++ * @param api -++ * the ASM API version implemented by this visitor. Must be one -++ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -++ * @param fv -++ * the field visitor to which this visitor must delegate method -++ * calls. May be null. -++ */ -++ public FieldVisitor(final int api, final FieldVisitor fv) { -++ if (api != Opcodes.ASM4 && api != Opcodes.ASM5) { -++ throw new IllegalArgumentException(); -++ } -++ this.api = api; -++ this.fv = fv; -++ } -++ -++ /** -++ * Visits an annotation of the field. -++ * -++ * @param desc -++ * the class descriptor of the annotation class. -++ * @param visible -++ * <tt>true</tt> if the annotation is visible at runtime. -++ * @return a visitor to visit the annotation values, or <tt>null</tt> if -++ * this visitor is not interested in visiting this annotation. -++ */ -++ public AnnotationVisitor visitAnnotation(String desc, boolean visible) { -++ if (fv != null) { -++ return fv.visitAnnotation(desc, visible); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits an annotation on the type of the field. -++ * -++ * @param typeRef -++ * a reference to the annotated type. The sort of this type -++ * reference must be {@link TypeReference#FIELD FIELD}. See -++ * {@link TypeReference}. -++ * @param typePath -++ * the path to the annotated type argument, wildcard bound, array -++ * element type, or static inner type within 'typeRef'. May be -++ * <tt>null</tt> if the annotation targets 'typeRef' as a whole. -++ * @param desc -++ * the class descriptor of the annotation class. -++ * @param visible -++ * <tt>true</tt> if the annotation is visible at runtime. -++ * @return a visitor to visit the annotation values, or <tt>null</tt> if -++ * this visitor is not interested in visiting this annotation. -++ */ -++ public AnnotationVisitor visitTypeAnnotation(int typeRef, -++ TypePath typePath, String desc, boolean visible) { -++ if (api < Opcodes.ASM5) { -++ throw new RuntimeException(); -++ } -++ if (fv != null) { -++ return fv.visitTypeAnnotation(typeRef, typePath, desc, visible); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits a non standard attribute of the field. -++ * -++ * @param attr -++ * an attribute. -++ */ -++ public void visitAttribute(Attribute attr) { -++ if (fv != null) { -++ fv.visitAttribute(attr); -++ } -++ } -++ -++ /** -++ * Visits the end of the field. This method, which is the last one to be -++ * called, is used to inform the visitor that all the annotations and -++ * attributes of the field have been visited. -++ */ -++ public void visitEnd() { -++ if (fv != null) { -++ fv.visitEnd(); -++ } -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/FieldWriter.java b/contrib/asm/src/org/objectweb/asm/FieldWriter.java -+new file mode 100644 -+index 0000000..84d92aa -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/FieldWriter.java -+@@ -0,0 +1,329 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * An {@link FieldVisitor} that generates Java fields in bytecode form. -++ * -++ * @author Eric Bruneton -++ */ -++final class FieldWriter extends FieldVisitor { -++ -++ /** -++ * The class writer to which this field must be added. -++ */ -++ private final ClassWriter cw; -++ -++ /** -++ * Access flags of this field. -++ */ -++ private final int access; -++ -++ /** -++ * The index of the constant pool item that contains the name of this -++ * method. -++ */ -++ private final int name; -++ -++ /** -++ * The index of the constant pool item that contains the descriptor of this -++ * field. -++ */ -++ private final int desc; -++ -++ /** -++ * The index of the constant pool item that contains the signature of this -++ * field. -++ */ -++ private int signature; -++ -++ /** -++ * The index of the constant pool item that contains the constant value of -++ * this field. -++ */ -++ private int value; -++ -++ /** -++ * The runtime visible annotations of this field. May be <tt>null</tt>. -++ */ -++ private AnnotationWriter anns; -++ -++ /** -++ * The runtime invisible annotations of this field. May be <tt>null</tt>. -++ */ -++ private AnnotationWriter ianns; -++ -++ /** -++ * The runtime visible type annotations of this field. May be <tt>null</tt>. -++ */ -++ private AnnotationWriter tanns; -++ -++ /** -++ * The runtime invisible type annotations of this field. May be -++ * <tt>null</tt>. -++ */ -++ private AnnotationWriter itanns; -++ -++ /** -++ * The non standard attributes of this field. May be <tt>null</tt>. -++ */ -++ private Attribute attrs; -++ -++ // ------------------------------------------------------------------------ -++ // Constructor -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Constructs a new {@link FieldWriter}. -++ * -++ * @param cw -++ * the class writer to which this field must be added. -++ * @param access -++ * the field's access flags (see {@link Opcodes}). -++ * @param name -++ * the field's name. -++ * @param desc -++ * the field's descriptor (see {@link Type}). -++ * @param signature -++ * the field's signature. May be <tt>null</tt>. -++ * @param value -++ * the field's constant value. May be <tt>null</tt>. -++ */ -++ FieldWriter(final ClassWriter cw, final int access, final String name, -++ final String desc, final String signature, final Object value) { -++ super(Opcodes.ASM5); -++ if (cw.firstField == null) { -++ cw.firstField = this; -++ } else { -++ cw.lastField.fv = this; -++ } -++ cw.lastField = this; -++ this.cw = cw; -++ this.access = access; -++ this.name = cw.newUTF8(name); -++ this.desc = cw.newUTF8(desc); -++ if (ClassReader.SIGNATURES && signature != null) { -++ this.signature = cw.newUTF8(signature); -++ } -++ if (value != null) { -++ this.value = cw.newConstItem(value).index; -++ } -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Implementation of the FieldVisitor abstract class -++ // ------------------------------------------------------------------------ -++ -++ @Override -++ public AnnotationVisitor visitAnnotation(final String desc, -++ final boolean visible) { -++ if (!ClassReader.ANNOTATIONS) { -++ return null; -++ } -++ ByteVector bv = new ByteVector(); -++ // write type, and reserve space for values count -++ bv.putShort(cw.newUTF8(desc)).putShort(0); -++ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); -++ if (visible) { -++ aw.next = anns; -++ anns = aw; -++ } else { -++ aw.next = ianns; -++ ianns = aw; -++ } -++ return aw; -++ } -++ -++ @Override -++ public AnnotationVisitor visitTypeAnnotation(final int typeRef, -++ final TypePath typePath, final String desc, final boolean visible) { -++ if (!ClassReader.ANNOTATIONS) { -++ return null; -++ } -++ ByteVector bv = new ByteVector(); -++ // write target_type and target_info -++ AnnotationWriter.putTarget(typeRef, typePath, bv); -++ // write type, and reserve space for values count -++ bv.putShort(cw.newUTF8(desc)).putShort(0); -++ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, -++ bv.length - 2); -++ if (visible) { -++ aw.next = tanns; -++ tanns = aw; -++ } else { -++ aw.next = itanns; -++ itanns = aw; -++ } -++ return aw; -++ } -++ -++ @Override -++ public void visitAttribute(final Attribute attr) { -++ attr.next = attrs; -++ attrs = attr; -++ } -++ -++ @Override -++ public void visitEnd() { -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Utility methods -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Returns the size of this field. -++ * -++ * @return the size of this field. -++ */ -++ int getSize() { -++ int size = 8; -++ if (value != 0) { -++ cw.newUTF8("ConstantValue"); -++ size += 8; -++ } -++ if ((access & Opcodes.ACC_SYNTHETIC) != 0) { -++ if ((cw.version & 0xFFFF) < Opcodes.V1_5 -++ || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { -++ cw.newUTF8("Synthetic"); -++ size += 6; -++ } -++ } -++ if ((access & Opcodes.ACC_DEPRECATED) != 0) { -++ cw.newUTF8("Deprecated"); -++ size += 6; -++ } -++ if (ClassReader.SIGNATURES && signature != 0) { -++ cw.newUTF8("Signature"); -++ size += 8; -++ } -++ if (ClassReader.ANNOTATIONS && anns != null) { -++ cw.newUTF8("RuntimeVisibleAnnotations"); -++ size += 8 + anns.getSize(); -++ } -++ if (ClassReader.ANNOTATIONS && ianns != null) { -++ cw.newUTF8("RuntimeInvisibleAnnotations"); -++ size += 8 + ianns.getSize(); -++ } -++ if (ClassReader.ANNOTATIONS && tanns != null) { -++ cw.newUTF8("RuntimeVisibleTypeAnnotations"); -++ size += 8 + tanns.getSize(); -++ } -++ if (ClassReader.ANNOTATIONS && itanns != null) { -++ cw.newUTF8("RuntimeInvisibleTypeAnnotations"); -++ size += 8 + itanns.getSize(); -++ } -++ if (attrs != null) { -++ size += attrs.getSize(cw, null, 0, -1, -1); -++ } -++ return size; -++ } -++ -++ /** -++ * Puts the content of this field into the given byte vector. -++ * -++ * @param out -++ * where the content of this field must be put. -++ */ -++ void put(final ByteVector out) { -++ final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC; -++ int mask = Opcodes.ACC_DEPRECATED | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE -++ | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR); -++ out.putShort(access & ~mask).putShort(name).putShort(desc); -++ int attributeCount = 0; -++ if (value != 0) { -++ ++attributeCount; -++ } -++ if ((access & Opcodes.ACC_SYNTHETIC) != 0) { -++ if ((cw.version & 0xFFFF) < Opcodes.V1_5 -++ || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { -++ ++attributeCount; -++ } -++ } -++ if ((access & Opcodes.ACC_DEPRECATED) != 0) { -++ ++attributeCount; -++ } -++ if (ClassReader.SIGNATURES && signature != 0) { -++ ++attributeCount; -++ } -++ if (ClassReader.ANNOTATIONS && anns != null) { -++ ++attributeCount; -++ } -++ if (ClassReader.ANNOTATIONS && ianns != null) { -++ ++attributeCount; -++ } -++ if (ClassReader.ANNOTATIONS && tanns != null) { -++ ++attributeCount; -++ } -++ if (ClassReader.ANNOTATIONS && itanns != null) { -++ ++attributeCount; -++ } -++ if (attrs != null) { -++ attributeCount += attrs.getCount(); -++ } -++ out.putShort(attributeCount); -++ if (value != 0) { -++ out.putShort(cw.newUTF8("ConstantValue")); -++ out.putInt(2).putShort(value); -++ } -++ if ((access & Opcodes.ACC_SYNTHETIC) != 0) { -++ if ((cw.version & 0xFFFF) < Opcodes.V1_5 -++ || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { -++ out.putShort(cw.newUTF8("Synthetic")).putInt(0); -++ } -++ } -++ if ((access & Opcodes.ACC_DEPRECATED) != 0) { -++ out.putShort(cw.newUTF8("Deprecated")).putInt(0); -++ } -++ if (ClassReader.SIGNATURES && signature != 0) { -++ out.putShort(cw.newUTF8("Signature")); -++ out.putInt(2).putShort(signature); -++ } -++ if (ClassReader.ANNOTATIONS && anns != null) { -++ out.putShort(cw.newUTF8("RuntimeVisibleAnnotations")); -++ anns.put(out); -++ } -++ if (ClassReader.ANNOTATIONS && ianns != null) { -++ out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations")); -++ ianns.put(out); -++ } -++ if (ClassReader.ANNOTATIONS && tanns != null) { -++ out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations")); -++ tanns.put(out); -++ } -++ if (ClassReader.ANNOTATIONS && itanns != null) { -++ out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations")); -++ itanns.put(out); -++ } -++ if (attrs != null) { -++ attrs.put(cw, null, 0, -1, -1, out); -++ } -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/Frame.java b/contrib/asm/src/org/objectweb/asm/Frame.java -+new file mode 100644 -+index 0000000..1f6106f -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/Frame.java -+@@ -0,0 +1,1462 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * Information about the input and output stack map frames of a basic block. -++ * -++ * @author Eric Bruneton -++ */ -++final class Frame { -++ -++ /* -++ * Frames are computed in a two steps process: during the visit of each -++ * instruction, the state of the frame at the end of current basic block is -++ * updated by simulating the action of the instruction on the previous state -++ * of this so called "output frame". In visitMaxs, a fix point algorithm is -++ * used to compute the "input frame" of each basic block, i.e. the stack map -++ * frame at the beginning of the basic block, starting from the input frame -++ * of the first basic block (which is computed from the method descriptor), -++ * and by using the previously computed output frames to compute the input -++ * state of the other blocks. -++ * -++ * All output and input frames are stored as arrays of integers. Reference -++ * and array types are represented by an index into a type table (which is -++ * not the same as the constant pool of the class, in order to avoid adding -++ * unnecessary constants in the pool - not all computed frames will end up -++ * being stored in the stack map table). This allows very fast type -++ * comparisons. -++ * -++ * Output stack map frames are computed relatively to the input frame of the -++ * basic block, which is not yet known when output frames are computed. It -++ * is therefore necessary to be able to represent abstract types such as -++ * "the type at position x in the input frame locals" or "the type at -++ * position x from the top of the input frame stack" or even "the type at -++ * position x in the input frame, with y more (or less) array dimensions". -++ * This explains the rather complicated type format used in output frames. -++ * -++ * This format is the following: DIM KIND VALUE (4, 4 and 24 bits). DIM is a -++ * signed number of array dimensions (from -8 to 7). KIND is either BASE, -++ * LOCAL or STACK. BASE is used for types that are not relative to the input -++ * frame. LOCAL is used for types that are relative to the input local -++ * variable types. STACK is used for types that are relative to the input -++ * stack types. VALUE depends on KIND. For LOCAL types, it is an index in -++ * the input local variable types. For STACK types, it is a position -++ * relatively to the top of input frame stack. For BASE types, it is either -++ * one of the constants defined below, or for OBJECT and UNINITIALIZED -++ * types, a tag and an index in the type table. -++ * -++ * Output frames can contain types of any kind and with a positive or -++ * negative dimension (and even unassigned types, represented by 0 - which -++ * does not correspond to any valid type value). Input frames can only -++ * contain BASE types of positive or null dimension. In all cases the type -++ * table contains only internal type names (array type descriptors are -++ * forbidden - dimensions must be represented through the DIM field). -++ * -++ * The LONG and DOUBLE types are always represented by using two slots (LONG -++ * + TOP or DOUBLE + TOP), for local variable types as well as in the -++ * operand stack. This is necessary to be able to simulate DUPx_y -++ * instructions, whose effect would be dependent on the actual type values -++ * if types were always represented by a single slot in the stack (and this -++ * is not possible, since actual type values are not always known - cf LOCAL -++ * and STACK type kinds). -++ */ -++ -++ /** -++ * Mask to get the dimension of a frame type. This dimension is a signed -++ * integer between -8 and 7. -++ */ -++ static final int DIM = 0xF0000000; -++ -++ /** -++ * Constant to be added to a type to get a type with one more dimension. -++ */ -++ static final int ARRAY_OF = 0x10000000; -++ -++ /** -++ * Constant to be added to a type to get a type with one less dimension. -++ */ -++ static final int ELEMENT_OF = 0xF0000000; -++ -++ /** -++ * Mask to get the kind of a frame type. -++ * -++ * @see #BASE -++ * @see #LOCAL -++ * @see #STACK -++ */ -++ static final int KIND = 0xF000000; -++ -++ /** -++ * Flag used for LOCAL and STACK types. Indicates that if this type happens -++ * to be a long or double type (during the computations of input frames), -++ * then it must be set to TOP because the second word of this value has been -++ * reused to store other data in the basic block. Hence the first word no -++ * longer stores a valid long or double value. -++ */ -++ static final int TOP_IF_LONG_OR_DOUBLE = 0x800000; -++ -++ /** -++ * Mask to get the value of a frame type. -++ */ -++ static final int VALUE = 0x7FFFFF; -++ -++ /** -++ * Mask to get the kind of base types. -++ */ -++ static final int BASE_KIND = 0xFF00000; -++ -++ /** -++ * Mask to get the value of base types. -++ */ -++ static final int BASE_VALUE = 0xFFFFF; -++ -++ /** -++ * Kind of the types that are not relative to an input stack map frame. -++ */ -++ static final int BASE = 0x1000000; -++ -++ /** -++ * Base kind of the base reference types. The BASE_VALUE of such types is an -++ * index into the type table. -++ */ -++ static final int OBJECT = BASE | 0x700000; -++ -++ /** -++ * Base kind of the uninitialized base types. The BASE_VALUE of such types -++ * in an index into the type table (the Item at that index contains both an -++ * instruction offset and an internal class name). -++ */ -++ static final int UNINITIALIZED = BASE | 0x800000; -++ -++ /** -++ * Kind of the types that are relative to the local variable types of an -++ * input stack map frame. The value of such types is a local variable index. -++ */ -++ private static final int LOCAL = 0x2000000; -++ -++ /** -++ * Kind of the the types that are relative to the stack of an input stack -++ * map frame. The value of such types is a position relatively to the top of -++ * this stack. -++ */ -++ private static final int STACK = 0x3000000; -++ -++ /** -++ * The TOP type. This is a BASE type. -++ */ -++ static final int TOP = BASE | 0; -++ -++ /** -++ * The BOOLEAN type. This is a BASE type mainly used for array types. -++ */ -++ static final int BOOLEAN = BASE | 9; -++ -++ /** -++ * The BYTE type. This is a BASE type mainly used for array types. -++ */ -++ static final int BYTE = BASE | 10; -++ -++ /** -++ * The CHAR type. This is a BASE type mainly used for array types. -++ */ -++ static final int CHAR = BASE | 11; -++ -++ /** -++ * The SHORT type. This is a BASE type mainly used for array types. -++ */ -++ static final int SHORT = BASE | 12; -++ -++ /** -++ * The INTEGER type. This is a BASE type. -++ */ -++ static final int INTEGER = BASE | 1; -++ -++ /** -++ * The FLOAT type. This is a BASE type. -++ */ -++ static final int FLOAT = BASE | 2; -++ -++ /** -++ * The DOUBLE type. This is a BASE type. -++ */ -++ static final int DOUBLE = BASE | 3; -++ -++ /** -++ * The LONG type. This is a BASE type. -++ */ -++ static final int LONG = BASE | 4; -++ -++ /** -++ * The NULL type. This is a BASE type. -++ */ -++ static final int NULL = BASE | 5; -++ -++ /** -++ * The UNINITIALIZED_THIS type. This is a BASE type. -++ */ -++ static final int UNINITIALIZED_THIS = BASE | 6; -++ -++ /** -++ * The stack size variation corresponding to each JVM instruction. This -++ * stack variation is equal to the size of the values produced by an -++ * instruction, minus the size of the values consumed by this instruction. -++ */ -++ static final int[] SIZE; -++ -++ /** -++ * Computes the stack size variation corresponding to each JVM instruction. -++ */ -++ static { -++ int i; -++ int[] b = new int[202]; -++ String s = "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDD" -++ + "CDCDEEEEEEEEEEEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCD" -++ + "CDCEEEEDDDDDDDCDCDCEFEFDDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFED" -++ + "DDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE"; -++ for (i = 0; i < b.length; ++i) { -++ b[i] = s.charAt(i) - 'E'; -++ } -++ SIZE = b; -++ -++ // code to generate the above string -++ // -++ // int NA = 0; // not applicable (unused opcode or variable size opcode) -++ // -++ // b = new int[] { -++ // 0, //NOP, // visitInsn -++ // 1, //ACONST_NULL, // - -++ // 1, //ICONST_M1, // - -++ // 1, //ICONST_0, // - -++ // 1, //ICONST_1, // - -++ // 1, //ICONST_2, // - -++ // 1, //ICONST_3, // - -++ // 1, //ICONST_4, // - -++ // 1, //ICONST_5, // - -++ // 2, //LCONST_0, // - -++ // 2, //LCONST_1, // - -++ // 1, //FCONST_0, // - -++ // 1, //FCONST_1, // - -++ // 1, //FCONST_2, // - -++ // 2, //DCONST_0, // - -++ // 2, //DCONST_1, // - -++ // 1, //BIPUSH, // visitIntInsn -++ // 1, //SIPUSH, // - -++ // 1, //LDC, // visitLdcInsn -++ // NA, //LDC_W, // - -++ // NA, //LDC2_W, // - -++ // 1, //ILOAD, // visitVarInsn -++ // 2, //LLOAD, // - -++ // 1, //FLOAD, // - -++ // 2, //DLOAD, // - -++ // 1, //ALOAD, // - -++ // NA, //ILOAD_0, // - -++ // NA, //ILOAD_1, // - -++ // NA, //ILOAD_2, // - -++ // NA, //ILOAD_3, // - -++ // NA, //LLOAD_0, // - -++ // NA, //LLOAD_1, // - -++ // NA, //LLOAD_2, // - -++ // NA, //LLOAD_3, // - -++ // NA, //FLOAD_0, // - -++ // NA, //FLOAD_1, // - -++ // NA, //FLOAD_2, // - -++ // NA, //FLOAD_3, // - -++ // NA, //DLOAD_0, // - -++ // NA, //DLOAD_1, // - -++ // NA, //DLOAD_2, // - -++ // NA, //DLOAD_3, // - -++ // NA, //ALOAD_0, // - -++ // NA, //ALOAD_1, // - -++ // NA, //ALOAD_2, // - -++ // NA, //ALOAD_3, // - -++ // -1, //IALOAD, // visitInsn -++ // 0, //LALOAD, // - -++ // -1, //FALOAD, // - -++ // 0, //DALOAD, // - -++ // -1, //AALOAD, // - -++ // -1, //BALOAD, // - -++ // -1, //CALOAD, // - -++ // -1, //SALOAD, // - -++ // -1, //ISTORE, // visitVarInsn -++ // -2, //LSTORE, // - -++ // -1, //FSTORE, // - -++ // -2, //DSTORE, // - -++ // -1, //ASTORE, // - -++ // NA, //ISTORE_0, // - -++ // NA, //ISTORE_1, // - -++ // NA, //ISTORE_2, // - -++ // NA, //ISTORE_3, // - -++ // NA, //LSTORE_0, // - -++ // NA, //LSTORE_1, // - -++ // NA, //LSTORE_2, // - -++ // NA, //LSTORE_3, // - -++ // NA, //FSTORE_0, // - -++ // NA, //FSTORE_1, // - -++ // NA, //FSTORE_2, // - -++ // NA, //FSTORE_3, // - -++ // NA, //DSTORE_0, // - -++ // NA, //DSTORE_1, // - -++ // NA, //DSTORE_2, // - -++ // NA, //DSTORE_3, // - -++ // NA, //ASTORE_0, // - -++ // NA, //ASTORE_1, // - -++ // NA, //ASTORE_2, // - -++ // NA, //ASTORE_3, // - -++ // -3, //IASTORE, // visitInsn -++ // -4, //LASTORE, // - -++ // -3, //FASTORE, // - -++ // -4, //DASTORE, // - -++ // -3, //AASTORE, // - -++ // -3, //BASTORE, // - -++ // -3, //CASTORE, // - -++ // -3, //SASTORE, // - -++ // -1, //POP, // - -++ // -2, //POP2, // - -++ // 1, //DUP, // - -++ // 1, //DUP_X1, // - -++ // 1, //DUP_X2, // - -++ // 2, //DUP2, // - -++ // 2, //DUP2_X1, // - -++ // 2, //DUP2_X2, // - -++ // 0, //SWAP, // - -++ // -1, //IADD, // - -++ // -2, //LADD, // - -++ // -1, //FADD, // - -++ // -2, //DADD, // - -++ // -1, //ISUB, // - -++ // -2, //LSUB, // - -++ // -1, //FSUB, // - -++ // -2, //DSUB, // - -++ // -1, //IMUL, // - -++ // -2, //LMUL, // - -++ // -1, //FMUL, // - -++ // -2, //DMUL, // - -++ // -1, //IDIV, // - -++ // -2, //LDIV, // - -++ // -1, //FDIV, // - -++ // -2, //DDIV, // - -++ // -1, //IREM, // - -++ // -2, //LREM, // - -++ // -1, //FREM, // - -++ // -2, //DREM, // - -++ // 0, //INEG, // - -++ // 0, //LNEG, // - -++ // 0, //FNEG, // - -++ // 0, //DNEG, // - -++ // -1, //ISHL, // - -++ // -1, //LSHL, // - -++ // -1, //ISHR, // - -++ // -1, //LSHR, // - -++ // -1, //IUSHR, // - -++ // -1, //LUSHR, // - -++ // -1, //IAND, // - -++ // -2, //LAND, // - -++ // -1, //IOR, // - -++ // -2, //LOR, // - -++ // -1, //IXOR, // - -++ // -2, //LXOR, // - -++ // 0, //IINC, // visitIincInsn -++ // 1, //I2L, // visitInsn -++ // 0, //I2F, // - -++ // 1, //I2D, // - -++ // -1, //L2I, // - -++ // -1, //L2F, // - -++ // 0, //L2D, // - -++ // 0, //F2I, // - -++ // 1, //F2L, // - -++ // 1, //F2D, // - -++ // -1, //D2I, // - -++ // 0, //D2L, // - -++ // -1, //D2F, // - -++ // 0, //I2B, // - -++ // 0, //I2C, // - -++ // 0, //I2S, // - -++ // -3, //LCMP, // - -++ // -1, //FCMPL, // - -++ // -1, //FCMPG, // - -++ // -3, //DCMPL, // - -++ // -3, //DCMPG, // - -++ // -1, //IFEQ, // visitJumpInsn -++ // -1, //IFNE, // - -++ // -1, //IFLT, // - -++ // -1, //IFGE, // - -++ // -1, //IFGT, // - -++ // -1, //IFLE, // - -++ // -2, //IF_ICMPEQ, // - -++ // -2, //IF_ICMPNE, // - -++ // -2, //IF_ICMPLT, // - -++ // -2, //IF_ICMPGE, // - -++ // -2, //IF_ICMPGT, // - -++ // -2, //IF_ICMPLE, // - -++ // -2, //IF_ACMPEQ, // - -++ // -2, //IF_ACMPNE, // - -++ // 0, //GOTO, // - -++ // 1, //JSR, // - -++ // 0, //RET, // visitVarInsn -++ // -1, //TABLESWITCH, // visiTableSwitchInsn -++ // -1, //LOOKUPSWITCH, // visitLookupSwitch -++ // -1, //IRETURN, // visitInsn -++ // -2, //LRETURN, // - -++ // -1, //FRETURN, // - -++ // -2, //DRETURN, // - -++ // -1, //ARETURN, // - -++ // 0, //RETURN, // - -++ // NA, //GETSTATIC, // visitFieldInsn -++ // NA, //PUTSTATIC, // - -++ // NA, //GETFIELD, // - -++ // NA, //PUTFIELD, // - -++ // NA, //INVOKEVIRTUAL, // visitMethodInsn -++ // NA, //INVOKESPECIAL, // - -++ // NA, //INVOKESTATIC, // - -++ // NA, //INVOKEINTERFACE, // - -++ // NA, //INVOKEDYNAMIC, // visitInvokeDynamicInsn -++ // 1, //NEW, // visitTypeInsn -++ // 0, //NEWARRAY, // visitIntInsn -++ // 0, //ANEWARRAY, // visitTypeInsn -++ // 0, //ARRAYLENGTH, // visitInsn -++ // NA, //ATHROW, // - -++ // 0, //CHECKCAST, // visitTypeInsn -++ // 0, //INSTANCEOF, // - -++ // -1, //MONITORENTER, // visitInsn -++ // -1, //MONITOREXIT, // - -++ // NA, //WIDE, // NOT VISITED -++ // NA, //MULTIANEWARRAY, // visitMultiANewArrayInsn -++ // -1, //IFNULL, // visitJumpInsn -++ // -1, //IFNONNULL, // - -++ // NA, //GOTO_W, // - -++ // NA, //JSR_W, // - -++ // }; -++ // for (i = 0; i < b.length; ++i) { -++ // System.err.print((char)('E' + b[i])); -++ // } -++ // System.err.println(); -++ } -++ -++ /** -++ * The label (i.e. basic block) to which these input and output stack map -++ * frames correspond. -++ */ -++ Label owner; -++ -++ /** -++ * The input stack map frame locals. -++ */ -++ int[] inputLocals; -++ -++ /** -++ * The input stack map frame stack. -++ */ -++ int[] inputStack; -++ -++ /** -++ * The output stack map frame locals. -++ */ -++ private int[] outputLocals; -++ -++ /** -++ * The output stack map frame stack. -++ */ -++ private int[] outputStack; -++ -++ /** -++ * Relative size of the output stack. The exact semantics of this field -++ * depends on the algorithm that is used. -++ * -++ * When only the maximum stack size is computed, this field is the size of -++ * the output stack relatively to the top of the input stack. -++ * -++ * When the stack map frames are completely computed, this field is the -++ * actual number of types in {@link #outputStack}. -++ */ -++ private int outputStackTop; -++ -++ /** -++ * Number of types that are initialized in the basic block. -++ * -++ * @see #initializations -++ */ -++ private int initializationCount; -++ -++ /** -++ * The types that are initialized in the basic block. A constructor -++ * invocation on an UNINITIALIZED or UNINITIALIZED_THIS type must replace -++ * <i>every occurence</i> of this type in the local variables and in the -++ * operand stack. This cannot be done during the first phase of the -++ * algorithm since, during this phase, the local variables and the operand -++ * stack are not completely computed. It is therefore necessary to store the -++ * types on which constructors are invoked in the basic block, in order to -++ * do this replacement during the second phase of the algorithm, where the -++ * frames are fully computed. Note that this array can contain types that -++ * are relative to input locals or to the input stack (see below for the -++ * description of the algorithm). -++ */ -++ private int[] initializations; -++ -++ /** -++ * Returns the output frame local variable type at the given index. -++ * -++ * @param local -++ * the index of the local that must be returned. -++ * @return the output frame local variable type at the given index. -++ */ -++ private int get(final int local) { -++ if (outputLocals == null || local >= outputLocals.length) { -++ // this local has never been assigned in this basic block, -++ // so it is still equal to its value in the input frame -++ return LOCAL | local; -++ } else { -++ int type = outputLocals[local]; -++ if (type == 0) { -++ // this local has never been assigned in this basic block, -++ // so it is still equal to its value in the input frame -++ type = outputLocals[local] = LOCAL | local; -++ } -++ return type; -++ } -++ } -++ -++ /** -++ * Sets the output frame local variable type at the given index. -++ * -++ * @param local -++ * the index of the local that must be set. -++ * @param type -++ * the value of the local that must be set. -++ */ -++ private void set(final int local, final int type) { -++ // creates and/or resizes the output local variables array if necessary -++ if (outputLocals == null) { -++ outputLocals = new int[10]; -++ } -++ int n = outputLocals.length; -++ if (local >= n) { -++ int[] t = new int[Math.max(local + 1, 2 * n)]; -++ System.arraycopy(outputLocals, 0, t, 0, n); -++ outputLocals = t; -++ } -++ // sets the local variable -++ outputLocals[local] = type; -++ } -++ -++ /** -++ * Pushes a new type onto the output frame stack. -++ * -++ * @param type -++ * the type that must be pushed. -++ */ -++ private void push(final int type) { -++ // creates and/or resizes the output stack array if necessary -++ if (outputStack == null) { -++ outputStack = new int[10]; -++ } -++ int n = outputStack.length; -++ if (outputStackTop >= n) { -++ int[] t = new int[Math.max(outputStackTop + 1, 2 * n)]; -++ System.arraycopy(outputStack, 0, t, 0, n); -++ outputStack = t; -++ } -++ // pushes the type on the output stack -++ outputStack[outputStackTop++] = type; -++ // updates the maximun height reached by the output stack, if needed -++ int top = owner.inputStackTop + outputStackTop; -++ if (top > owner.outputStackMax) { -++ owner.outputStackMax = top; -++ } -++ } -++ -++ /** -++ * Pushes a new type onto the output frame stack. -++ * -++ * @param cw -++ * the ClassWriter to which this label belongs. -++ * @param desc -++ * the descriptor of the type to be pushed. Can also be a method -++ * descriptor (in this case this method pushes its return type -++ * onto the output frame stack). -++ */ -++ private void push(final ClassWriter cw, final String desc) { -++ int type = type(cw, desc); -++ if (type != 0) { -++ push(type); -++ if (type == LONG || type == DOUBLE) { -++ push(TOP); -++ } -++ } -++ } -++ -++ /** -++ * Returns the int encoding of the given type. -++ * -++ * @param cw -++ * the ClassWriter to which this label belongs. -++ * @param desc -++ * a type descriptor. -++ * @return the int encoding of the given type. -++ */ -++ private static int type(final ClassWriter cw, final String desc) { -++ String t; -++ int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0; -++ switch (desc.charAt(index)) { -++ case 'V': -++ return 0; -++ case 'Z': -++ case 'C': -++ case 'B': -++ case 'S': -++ case 'I': -++ return INTEGER; -++ case 'F': -++ return FLOAT; -++ case 'J': -++ return LONG; -++ case 'D': -++ return DOUBLE; -++ case 'L': -++ // stores the internal name, not the descriptor! -++ t = desc.substring(index + 1, desc.length() - 1); -++ return OBJECT | cw.addType(t); -++ // case '[': -++ default: -++ // extracts the dimensions and the element type -++ int data; -++ int dims = index + 1; -++ while (desc.charAt(dims) == '[') { -++ ++dims; -++ } -++ switch (desc.charAt(dims)) { -++ case 'Z': -++ data = BOOLEAN; -++ break; -++ case 'C': -++ data = CHAR; -++ break; -++ case 'B': -++ data = BYTE; -++ break; -++ case 'S': -++ data = SHORT; -++ break; -++ case 'I': -++ data = INTEGER; -++ break; -++ case 'F': -++ data = FLOAT; -++ break; -++ case 'J': -++ data = LONG; -++ break; -++ case 'D': -++ data = DOUBLE; -++ break; -++ // case 'L': -++ default: -++ // stores the internal name, not the descriptor -++ t = desc.substring(dims + 1, desc.length() - 1); -++ data = OBJECT | cw.addType(t); -++ } -++ return (dims - index) << 28 | data; -++ } -++ } -++ -++ /** -++ * Pops a type from the output frame stack and returns its value. -++ * -++ * @return the type that has been popped from the output frame stack. -++ */ -++ private int pop() { -++ if (outputStackTop > 0) { -++ return outputStack[--outputStackTop]; -++ } else { -++ // if the output frame stack is empty, pops from the input stack -++ return STACK | -(--owner.inputStackTop); -++ } -++ } -++ -++ /** -++ * Pops the given number of types from the output frame stack. -++ * -++ * @param elements -++ * the number of types that must be popped. -++ */ -++ private void pop(final int elements) { -++ if (outputStackTop >= elements) { -++ outputStackTop -= elements; -++ } else { -++ // if the number of elements to be popped is greater than the number -++ // of elements in the output stack, clear it, and pops the remaining -++ // elements from the input stack. -++ owner.inputStackTop -= elements - outputStackTop; -++ outputStackTop = 0; -++ } -++ } -++ -++ /** -++ * Pops a type from the output frame stack. -++ * -++ * @param desc -++ * the descriptor of the type to be popped. Can also be a method -++ * descriptor (in this case this method pops the types -++ * corresponding to the method arguments). -++ */ -++ private void pop(final String desc) { -++ char c = desc.charAt(0); -++ if (c == '(') { -++ pop((Type.getArgumentsAndReturnSizes(desc) >> 2) - 1); -++ } else if (c == 'J' || c == 'D') { -++ pop(2); -++ } else { -++ pop(1); -++ } -++ } -++ -++ /** -++ * Adds a new type to the list of types on which a constructor is invoked in -++ * the basic block. -++ * -++ * @param var -++ * a type on a which a constructor is invoked. -++ */ -++ private void init(final int var) { -++ // creates and/or resizes the initializations array if necessary -++ if (initializations == null) { -++ initializations = new int[2]; -++ } -++ int n = initializations.length; -++ if (initializationCount >= n) { -++ int[] t = new int[Math.max(initializationCount + 1, 2 * n)]; -++ System.arraycopy(initializations, 0, t, 0, n); -++ initializations = t; -++ } -++ // stores the type to be initialized -++ initializations[initializationCount++] = var; -++ } -++ -++ /** -++ * Replaces the given type with the appropriate type if it is one of the -++ * types on which a constructor is invoked in the basic block. -++ * -++ * @param cw -++ * the ClassWriter to which this label belongs. -++ * @param t -++ * a type -++ * @return t or, if t is one of the types on which a constructor is invoked -++ * in the basic block, the type corresponding to this constructor. -++ */ -++ private int init(final ClassWriter cw, final int t) { -++ int s; -++ if (t == UNINITIALIZED_THIS) { -++ s = OBJECT | cw.addType(cw.thisName); -++ } else if ((t & (DIM | BASE_KIND)) == UNINITIALIZED) { -++ String type = cw.typeTable[t & BASE_VALUE].strVal1; -++ s = OBJECT | cw.addType(type); -++ } else { -++ return t; -++ } -++ for (int j = 0; j < initializationCount; ++j) { -++ int u = initializations[j]; -++ int dim = u & DIM; -++ int kind = u & KIND; -++ if (kind == LOCAL) { -++ u = dim + inputLocals[u & VALUE]; -++ } else if (kind == STACK) { -++ u = dim + inputStack[inputStack.length - (u & VALUE)]; -++ } -++ if (t == u) { -++ return s; -++ } -++ } -++ return t; -++ } -++ -++ /** -++ * Initializes the input frame of the first basic block from the method -++ * descriptor. -++ * -++ * @param cw -++ * the ClassWriter to which this label belongs. -++ * @param access -++ * the access flags of the method to which this label belongs. -++ * @param args -++ * the formal parameter types of this method. -++ * @param maxLocals -++ * the maximum number of local variables of this method. -++ */ -++ void initInputFrame(final ClassWriter cw, final int access, -++ final Type[] args, final int maxLocals) { -++ inputLocals = new int[maxLocals]; -++ inputStack = new int[0]; -++ int i = 0; -++ if ((access & Opcodes.ACC_STATIC) == 0) { -++ if ((access & MethodWriter.ACC_CONSTRUCTOR) == 0) { -++ inputLocals[i++] = OBJECT | cw.addType(cw.thisName); -++ } else { -++ inputLocals[i++] = UNINITIALIZED_THIS; -++ } -++ } -++ for (int j = 0; j < args.length; ++j) { -++ int t = type(cw, args[j].getDescriptor()); -++ inputLocals[i++] = t; -++ if (t == LONG || t == DOUBLE) { -++ inputLocals[i++] = TOP; -++ } -++ } -++ while (i < maxLocals) { -++ inputLocals[i++] = TOP; -++ } -++ } -++ -++ /** -++ * Simulates the action of the given instruction on the output stack frame. -++ * -++ * @param opcode -++ * the opcode of the instruction. -++ * @param arg -++ * the operand of the instruction, if any. -++ * @param cw -++ * the class writer to which this label belongs. -++ * @param item -++ * the operand of the instructions, if any. -++ */ -++ void execute(final int opcode, final int arg, final ClassWriter cw, -++ final Item item) { -++ int t1, t2, t3, t4; -++ switch (opcode) { -++ case Opcodes.NOP: -++ case Opcodes.INEG: -++ case Opcodes.LNEG: -++ case Opcodes.FNEG: -++ case Opcodes.DNEG: -++ case Opcodes.I2B: -++ case Opcodes.I2C: -++ case Opcodes.I2S: -++ case Opcodes.GOTO: -++ case Opcodes.RETURN: -++ break; -++ case Opcodes.ACONST_NULL: -++ push(NULL); -++ break; -++ case Opcodes.ICONST_M1: -++ case Opcodes.ICONST_0: -++ case Opcodes.ICONST_1: -++ case Opcodes.ICONST_2: -++ case Opcodes.ICONST_3: -++ case Opcodes.ICONST_4: -++ case Opcodes.ICONST_5: -++ case Opcodes.BIPUSH: -++ case Opcodes.SIPUSH: -++ case Opcodes.ILOAD: -++ push(INTEGER); -++ break; -++ case Opcodes.LCONST_0: -++ case Opcodes.LCONST_1: -++ case Opcodes.LLOAD: -++ push(LONG); -++ push(TOP); -++ break; -++ case Opcodes.FCONST_0: -++ case Opcodes.FCONST_1: -++ case Opcodes.FCONST_2: -++ case Opcodes.FLOAD: -++ push(FLOAT); -++ break; -++ case Opcodes.DCONST_0: -++ case Opcodes.DCONST_1: -++ case Opcodes.DLOAD: -++ push(DOUBLE); -++ push(TOP); -++ break; -++ case Opcodes.LDC: -++ switch (item.type) { -++ case ClassWriter.INT: -++ push(INTEGER); -++ break; -++ case ClassWriter.LONG: -++ push(LONG); -++ push(TOP); -++ break; -++ case ClassWriter.FLOAT: -++ push(FLOAT); -++ break; -++ case ClassWriter.DOUBLE: -++ push(DOUBLE); -++ push(TOP); -++ break; -++ case ClassWriter.CLASS: -++ push(OBJECT | cw.addType("java/lang/Class")); -++ break; -++ case ClassWriter.STR: -++ push(OBJECT | cw.addType("java/lang/String")); -++ break; -++ case ClassWriter.MTYPE: -++ push(OBJECT | cw.addType("java/lang/invoke/MethodType")); -++ break; -++ // case ClassWriter.HANDLE_BASE + [1..9]: -++ default: -++ push(OBJECT | cw.addType("java/lang/invoke/MethodHandle")); -++ } -++ break; -++ case Opcodes.ALOAD: -++ push(get(arg)); -++ break; -++ case Opcodes.IALOAD: -++ case Opcodes.BALOAD: -++ case Opcodes.CALOAD: -++ case Opcodes.SALOAD: -++ pop(2); -++ push(INTEGER); -++ break; -++ case Opcodes.LALOAD: -++ case Opcodes.D2L: -++ pop(2); -++ push(LONG); -++ push(TOP); -++ break; -++ case Opcodes.FALOAD: -++ pop(2); -++ push(FLOAT); -++ break; -++ case Opcodes.DALOAD: -++ case Opcodes.L2D: -++ pop(2); -++ push(DOUBLE); -++ push(TOP); -++ break; -++ case Opcodes.AALOAD: -++ pop(1); -++ t1 = pop(); -++ push(ELEMENT_OF + t1); -++ break; -++ case Opcodes.ISTORE: -++ case Opcodes.FSTORE: -++ case Opcodes.ASTORE: -++ t1 = pop(); -++ set(arg, t1); -++ if (arg > 0) { -++ t2 = get(arg - 1); -++ // if t2 is of kind STACK or LOCAL we cannot know its size! -++ if (t2 == LONG || t2 == DOUBLE) { -++ set(arg - 1, TOP); -++ } else if ((t2 & KIND) != BASE) { -++ set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE); -++ } -++ } -++ break; -++ case Opcodes.LSTORE: -++ case Opcodes.DSTORE: -++ pop(1); -++ t1 = pop(); -++ set(arg, t1); -++ set(arg + 1, TOP); -++ if (arg > 0) { -++ t2 = get(arg - 1); -++ // if t2 is of kind STACK or LOCAL we cannot know its size! -++ if (t2 == LONG || t2 == DOUBLE) { -++ set(arg - 1, TOP); -++ } else if ((t2 & KIND) != BASE) { -++ set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE); -++ } -++ } -++ break; -++ case Opcodes.IASTORE: -++ case Opcodes.BASTORE: -++ case Opcodes.CASTORE: -++ case Opcodes.SASTORE: -++ case Opcodes.FASTORE: -++ case Opcodes.AASTORE: -++ pop(3); -++ break; -++ case Opcodes.LASTORE: -++ case Opcodes.DASTORE: -++ pop(4); -++ break; -++ case Opcodes.POP: -++ case Opcodes.IFEQ: -++ case Opcodes.IFNE: -++ case Opcodes.IFLT: -++ case Opcodes.IFGE: -++ case Opcodes.IFGT: -++ case Opcodes.IFLE: -++ case Opcodes.IRETURN: -++ case Opcodes.FRETURN: -++ case Opcodes.ARETURN: -++ case Opcodes.TABLESWITCH: -++ case Opcodes.LOOKUPSWITCH: -++ case Opcodes.ATHROW: -++ case Opcodes.MONITORENTER: -++ case Opcodes.MONITOREXIT: -++ case Opcodes.IFNULL: -++ case Opcodes.IFNONNULL: -++ pop(1); -++ break; -++ case Opcodes.POP2: -++ case Opcodes.IF_ICMPEQ: -++ case Opcodes.IF_ICMPNE: -++ case Opcodes.IF_ICMPLT: -++ case Opcodes.IF_ICMPGE: -++ case Opcodes.IF_ICMPGT: -++ case Opcodes.IF_ICMPLE: -++ case Opcodes.IF_ACMPEQ: -++ case Opcodes.IF_ACMPNE: -++ case Opcodes.LRETURN: -++ case Opcodes.DRETURN: -++ pop(2); -++ break; -++ case Opcodes.DUP: -++ t1 = pop(); -++ push(t1); -++ push(t1); -++ break; -++ case Opcodes.DUP_X1: -++ t1 = pop(); -++ t2 = pop(); -++ push(t1); -++ push(t2); -++ push(t1); -++ break; -++ case Opcodes.DUP_X2: -++ t1 = pop(); -++ t2 = pop(); -++ t3 = pop(); -++ push(t1); -++ push(t3); -++ push(t2); -++ push(t1); -++ break; -++ case Opcodes.DUP2: -++ t1 = pop(); -++ t2 = pop(); -++ push(t2); -++ push(t1); -++ push(t2); -++ push(t1); -++ break; -++ case Opcodes.DUP2_X1: -++ t1 = pop(); -++ t2 = pop(); -++ t3 = pop(); -++ push(t2); -++ push(t1); -++ push(t3); -++ push(t2); -++ push(t1); -++ break; -++ case Opcodes.DUP2_X2: -++ t1 = pop(); -++ t2 = pop(); -++ t3 = pop(); -++ t4 = pop(); -++ push(t2); -++ push(t1); -++ push(t4); -++ push(t3); -++ push(t2); -++ push(t1); -++ break; -++ case Opcodes.SWAP: -++ t1 = pop(); -++ t2 = pop(); -++ push(t1); -++ push(t2); -++ break; -++ case Opcodes.IADD: -++ case Opcodes.ISUB: -++ case Opcodes.IMUL: -++ case Opcodes.IDIV: -++ case Opcodes.IREM: -++ case Opcodes.IAND: -++ case Opcodes.IOR: -++ case Opcodes.IXOR: -++ case Opcodes.ISHL: -++ case Opcodes.ISHR: -++ case Opcodes.IUSHR: -++ case Opcodes.L2I: -++ case Opcodes.D2I: -++ case Opcodes.FCMPL: -++ case Opcodes.FCMPG: -++ pop(2); -++ push(INTEGER); -++ break; -++ case Opcodes.LADD: -++ case Opcodes.LSUB: -++ case Opcodes.LMUL: -++ case Opcodes.LDIV: -++ case Opcodes.LREM: -++ case Opcodes.LAND: -++ case Opcodes.LOR: -++ case Opcodes.LXOR: -++ pop(4); -++ push(LONG); -++ push(TOP); -++ break; -++ case Opcodes.FADD: -++ case Opcodes.FSUB: -++ case Opcodes.FMUL: -++ case Opcodes.FDIV: -++ case Opcodes.FREM: -++ case Opcodes.L2F: -++ case Opcodes.D2F: -++ pop(2); -++ push(FLOAT); -++ break; -++ case Opcodes.DADD: -++ case Opcodes.DSUB: -++ case Opcodes.DMUL: -++ case Opcodes.DDIV: -++ case Opcodes.DREM: -++ pop(4); -++ push(DOUBLE); -++ push(TOP); -++ break; -++ case Opcodes.LSHL: -++ case Opcodes.LSHR: -++ case Opcodes.LUSHR: -++ pop(3); -++ push(LONG); -++ push(TOP); -++ break; -++ case Opcodes.IINC: -++ set(arg, INTEGER); -++ break; -++ case Opcodes.I2L: -++ case Opcodes.F2L: -++ pop(1); -++ push(LONG); -++ push(TOP); -++ break; -++ case Opcodes.I2F: -++ pop(1); -++ push(FLOAT); -++ break; -++ case Opcodes.I2D: -++ case Opcodes.F2D: -++ pop(1); -++ push(DOUBLE); -++ push(TOP); -++ break; -++ case Opcodes.F2I: -++ case Opcodes.ARRAYLENGTH: -++ case Opcodes.INSTANCEOF: -++ pop(1); -++ push(INTEGER); -++ break; -++ case Opcodes.LCMP: -++ case Opcodes.DCMPL: -++ case Opcodes.DCMPG: -++ pop(4); -++ push(INTEGER); -++ break; -++ case Opcodes.JSR: -++ case Opcodes.RET: -++ throw new RuntimeException( -++ "JSR/RET are not supported with computeFrames option"); -++ case Opcodes.GETSTATIC: -++ push(cw, item.strVal3); -++ break; -++ case Opcodes.PUTSTATIC: -++ pop(item.strVal3); -++ break; -++ case Opcodes.GETFIELD: -++ pop(1); -++ push(cw, item.strVal3); -++ break; -++ case Opcodes.PUTFIELD: -++ pop(item.strVal3); -++ pop(); -++ break; -++ case Opcodes.INVOKEVIRTUAL: -++ case Opcodes.INVOKESPECIAL: -++ case Opcodes.INVOKESTATIC: -++ case Opcodes.INVOKEINTERFACE: -++ pop(item.strVal3); -++ if (opcode != Opcodes.INVOKESTATIC) { -++ t1 = pop(); -++ if (opcode == Opcodes.INVOKESPECIAL -++ && item.strVal2.charAt(0) == '<') { -++ init(t1); -++ } -++ } -++ push(cw, item.strVal3); -++ break; -++ case Opcodes.INVOKEDYNAMIC: -++ pop(item.strVal2); -++ push(cw, item.strVal2); -++ break; -++ case Opcodes.NEW: -++ push(UNINITIALIZED | cw.addUninitializedType(item.strVal1, arg)); -++ break; -++ case Opcodes.NEWARRAY: -++ pop(); -++ switch (arg) { -++ case Opcodes.T_BOOLEAN: -++ push(ARRAY_OF | BOOLEAN); -++ break; -++ case Opcodes.T_CHAR: -++ push(ARRAY_OF | CHAR); -++ break; -++ case Opcodes.T_BYTE: -++ push(ARRAY_OF | BYTE); -++ break; -++ case Opcodes.T_SHORT: -++ push(ARRAY_OF | SHORT); -++ break; -++ case Opcodes.T_INT: -++ push(ARRAY_OF | INTEGER); -++ break; -++ case Opcodes.T_FLOAT: -++ push(ARRAY_OF | FLOAT); -++ break; -++ case Opcodes.T_DOUBLE: -++ push(ARRAY_OF | DOUBLE); -++ break; -++ // case Opcodes.T_LONG: -++ default: -++ push(ARRAY_OF | LONG); -++ break; -++ } -++ break; -++ case Opcodes.ANEWARRAY: -++ String s = item.strVal1; -++ pop(); -++ if (s.charAt(0) == '[') { -++ push(cw, '[' + s); -++ } else { -++ push(ARRAY_OF | OBJECT | cw.addType(s)); -++ } -++ break; -++ case Opcodes.CHECKCAST: -++ s = item.strVal1; -++ pop(); -++ if (s.charAt(0) == '[') { -++ push(cw, s); -++ } else { -++ push(OBJECT | cw.addType(s)); -++ } -++ break; -++ // case Opcodes.MULTIANEWARRAY: -++ default: -++ pop(arg); -++ push(cw, item.strVal1); -++ break; -++ } -++ } -++ -++ /** -++ * Merges the input frame of the given basic block with the input and output -++ * frames of this basic block. Returns <tt>true</tt> if the input frame of -++ * the given label has been changed by this operation. -++ * -++ * @param cw -++ * the ClassWriter to which this label belongs. -++ * @param frame -++ * the basic block whose input frame must be updated. -++ * @param edge -++ * the kind of the {@link Edge} between this label and 'label'. -++ * See {@link Edge#info}. -++ * @return <tt>true</tt> if the input frame of the given label has been -++ * changed by this operation. -++ */ -++ boolean merge(final ClassWriter cw, final Frame frame, final int edge) { -++ boolean changed = false; -++ int i, s, dim, kind, t; -++ -++ int nLocal = inputLocals.length; -++ int nStack = inputStack.length; -++ if (frame.inputLocals == null) { -++ frame.inputLocals = new int[nLocal]; -++ changed = true; -++ } -++ -++ for (i = 0; i < nLocal; ++i) { -++ if (outputLocals != null && i < outputLocals.length) { -++ s = outputLocals[i]; -++ if (s == 0) { -++ t = inputLocals[i]; -++ } else { -++ dim = s & DIM; -++ kind = s & KIND; -++ if (kind == BASE) { -++ t = s; -++ } else { -++ if (kind == LOCAL) { -++ t = dim + inputLocals[s & VALUE]; -++ } else { -++ t = dim + inputStack[nStack - (s & VALUE)]; -++ } -++ if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 -++ && (t == LONG || t == DOUBLE)) { -++ t = TOP; -++ } -++ } -++ } -++ } else { -++ t = inputLocals[i]; -++ } -++ if (initializations != null) { -++ t = init(cw, t); -++ } -++ changed |= merge(cw, t, frame.inputLocals, i); -++ } -++ -++ if (edge > 0) { -++ for (i = 0; i < nLocal; ++i) { -++ t = inputLocals[i]; -++ changed |= merge(cw, t, frame.inputLocals, i); -++ } -++ if (frame.inputStack == null) { -++ frame.inputStack = new int[1]; -++ changed = true; -++ } -++ changed |= merge(cw, edge, frame.inputStack, 0); -++ return changed; -++ } -++ -++ int nInputStack = inputStack.length + owner.inputStackTop; -++ if (frame.inputStack == null) { -++ frame.inputStack = new int[nInputStack + outputStackTop]; -++ changed = true; -++ } -++ -++ for (i = 0; i < nInputStack; ++i) { -++ t = inputStack[i]; -++ if (initializations != null) { -++ t = init(cw, t); -++ } -++ changed |= merge(cw, t, frame.inputStack, i); -++ } -++ for (i = 0; i < outputStackTop; ++i) { -++ s = outputStack[i]; -++ dim = s & DIM; -++ kind = s & KIND; -++ if (kind == BASE) { -++ t = s; -++ } else { -++ if (kind == LOCAL) { -++ t = dim + inputLocals[s & VALUE]; -++ } else { -++ t = dim + inputStack[nStack - (s & VALUE)]; -++ } -++ if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 -++ && (t == LONG || t == DOUBLE)) { -++ t = TOP; -++ } -++ } -++ if (initializations != null) { -++ t = init(cw, t); -++ } -++ changed |= merge(cw, t, frame.inputStack, nInputStack + i); -++ } -++ return changed; -++ } -++ -++ /** -++ * Merges the type at the given index in the given type array with the given -++ * type. Returns <tt>true</tt> if the type array has been modified by this -++ * operation. -++ * -++ * @param cw -++ * the ClassWriter to which this label belongs. -++ * @param t -++ * the type with which the type array element must be merged. -++ * @param types -++ * an array of types. -++ * @param index -++ * the index of the type that must be merged in 'types'. -++ * @return <tt>true</tt> if the type array has been modified by this -++ * operation. -++ */ -++ private static boolean merge(final ClassWriter cw, int t, -++ final int[] types, final int index) { -++ int u = types[index]; -++ if (u == t) { -++ // if the types are equal, merge(u,t)=u, so there is no change -++ return false; -++ } -++ if ((t & ~DIM) == NULL) { -++ if (u == NULL) { -++ return false; -++ } -++ t = NULL; -++ } -++ if (u == 0) { -++ // if types[index] has never been assigned, merge(u,t)=t -++ types[index] = t; -++ return true; -++ } -++ int v; -++ if ((u & BASE_KIND) == OBJECT || (u & DIM) != 0) { -++ // if u is a reference type of any dimension -++ if (t == NULL) { -++ // if t is the NULL type, merge(u,t)=u, so there is no change -++ return false; -++ } else if ((t & (DIM | BASE_KIND)) == (u & (DIM | BASE_KIND))) { -++ // if t and u have the same dimension and same base kind -++ if ((u & BASE_KIND) == OBJECT) { -++ // if t is also a reference type, and if u and t have the -++ // same dimension merge(u,t) = dim(t) | common parent of the -++ // element types of u and t -++ v = (t & DIM) | OBJECT -++ | cw.getMergedType(t & BASE_VALUE, u & BASE_VALUE); -++ } else { -++ // if u and t are array types, but not with the same element -++ // type, merge(u,t) = dim(u) - 1 | java/lang/Object -++ int vdim = ELEMENT_OF + (u & DIM); -++ v = vdim | OBJECT | cw.addType("java/lang/Object"); -++ } -++ } else if ((t & BASE_KIND) == OBJECT || (t & DIM) != 0) { -++ // if t is any other reference or array type, the merged type -++ // is min(udim, tdim) | java/lang/Object, where udim is the -++ // array dimension of u, minus 1 if u is an array type with a -++ // primitive element type (and similarly for tdim). -++ int tdim = (((t & DIM) == 0 || (t & BASE_KIND) == OBJECT) ? 0 -++ : ELEMENT_OF) + (t & DIM); -++ int udim = (((u & DIM) == 0 || (u & BASE_KIND) == OBJECT) ? 0 -++ : ELEMENT_OF) + (u & DIM); -++ v = Math.min(tdim, udim) | OBJECT -++ | cw.addType("java/lang/Object"); -++ } else { -++ // if t is any other type, merge(u,t)=TOP -++ v = TOP; -++ } -++ } else if (u == NULL) { -++ // if u is the NULL type, merge(u,t)=t, -++ // or TOP if t is not a reference type -++ v = (t & BASE_KIND) == OBJECT || (t & DIM) != 0 ? t : TOP; -++ } else { -++ // if u is any other type, merge(u,t)=TOP whatever t -++ v = TOP; -++ } -++ if (u != v) { -++ types[index] = v; -++ return true; -++ } -++ return false; -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/Handle.java b/contrib/asm/src/org/objectweb/asm/Handle.java -+new file mode 100644 -+index 0000000..a627911 -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/Handle.java -+@@ -0,0 +1,170 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++ -++package org.objectweb.asm; -++ -++/** -++ * A reference to a field or a method. -++ * -++ * @author Remi Forax -++ * @author Eric Bruneton -++ */ -++public final class Handle { -++ -++ /** -++ * The kind of field or method designated by this Handle. Should be -++ * {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, -++ * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, -++ * {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, -++ * {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or -++ * {@link Opcodes#H_INVOKEINTERFACE}. -++ */ -++ final int tag; -++ -++ /** -++ * The internal name of the class that owns the field or method designated -++ * by this handle. -++ */ -++ final String owner; -++ -++ /** -++ * The name of the field or method designated by this handle. -++ */ -++ final String name; -++ -++ /** -++ * The descriptor of the field or method designated by this handle. -++ */ -++ final String desc; -++ -++ /** -++ * Constructs a new field or method handle. -++ * -++ * @param tag -++ * the kind of field or method designated by this Handle. Must be -++ * {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, -++ * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, -++ * {@link Opcodes#H_INVOKEVIRTUAL}, -++ * {@link Opcodes#H_INVOKESTATIC}, -++ * {@link Opcodes#H_INVOKESPECIAL}, -++ * {@link Opcodes#H_NEWINVOKESPECIAL} or -++ * {@link Opcodes#H_INVOKEINTERFACE}. -++ * @param owner -++ * the internal name of the class that owns the field or method -++ * designated by this handle. -++ * @param name -++ * the name of the field or method designated by this handle. -++ * @param desc -++ * the descriptor of the field or method designated by this -++ * handle. -++ */ -++ public Handle(int tag, String owner, String name, String desc) { -++ this.tag = tag; -++ this.owner = owner; -++ this.name = name; -++ this.desc = desc; -++ } -++ -++ /** -++ * Returns the kind of field or method designated by this handle. -++ * -++ * @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, -++ * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, -++ * {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, -++ * {@link Opcodes#H_INVOKESPECIAL}, -++ * {@link Opcodes#H_NEWINVOKESPECIAL} or -++ * {@link Opcodes#H_INVOKEINTERFACE}. -++ */ -++ public int getTag() { -++ return tag; -++ } -++ -++ /** -++ * Returns the internal name of the class that owns the field or method -++ * designated by this handle. -++ * -++ * @return the internal name of the class that owns the field or method -++ * designated by this handle. -++ */ -++ public String getOwner() { -++ return owner; -++ } -++ -++ /** -++ * Returns the name of the field or method designated by this handle. -++ * -++ * @return the name of the field or method designated by this handle. -++ */ -++ public String getName() { -++ return name; -++ } -++ -++ /** -++ * Returns the descriptor of the field or method designated by this handle. -++ * -++ * @return the descriptor of the field or method designated by this handle. -++ */ -++ public String getDesc() { -++ return desc; -++ } -++ -++ @Override -++ public boolean equals(Object obj) { -++ if (obj == this) { -++ return true; -++ } -++ if (!(obj instanceof Handle)) { -++ return false; -++ } -++ Handle h = (Handle) obj; -++ return tag == h.tag && owner.equals(h.owner) && name.equals(h.name) -++ && desc.equals(h.desc); -++ } -++ -++ @Override -++ public int hashCode() { -++ return tag + owner.hashCode() * name.hashCode() * desc.hashCode(); -++ } -++ -++ /** -++ * Returns the textual representation of this handle. The textual -++ * representation is: -++ * -++ * <pre> -++ * owner '.' name desc ' ' '(' tag ')' -++ * </pre> -++ * -++ * . As this format is unambiguous, it can be parsed if necessary. -++ */ -++ @Override -++ public String toString() { -++ return owner + '.' + name + desc + " (" + tag + ')'; -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/Handler.java b/contrib/asm/src/org/objectweb/asm/Handler.java -+new file mode 100644 -+index 0000000..b24591d -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/Handler.java -+@@ -0,0 +1,121 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * Information about an exception handler block. -++ * -++ * @author Eric Bruneton -++ */ -++class Handler { -++ -++ /** -++ * Beginning of the exception handler's scope (inclusive). -++ */ -++ Label start; -++ -++ /** -++ * End of the exception handler's scope (exclusive). -++ */ -++ Label end; -++ -++ /** -++ * Beginning of the exception handler's code. -++ */ -++ Label handler; -++ -++ /** -++ * Internal name of the type of exceptions handled by this handler, or -++ * <tt>null</tt> to catch any exceptions. -++ */ -++ String desc; -++ -++ /** -++ * Constant pool index of the internal name of the type of exceptions -++ * handled by this handler, or 0 to catch any exceptions. -++ */ -++ int type; -++ -++ /** -++ * Next exception handler block info. -++ */ -++ Handler next; -++ -++ /** -++ * Removes the range between start and end from the given exception -++ * handlers. -++ * -++ * @param h -++ * an exception handler list. -++ * @param start -++ * the start of the range to be removed. -++ * @param end -++ * the end of the range to be removed. Maybe null. -++ * @return the exception handler list with the start-end range removed. -++ */ -++ static Handler remove(Handler h, Label start, Label end) { -++ if (h == null) { -++ return null; -++ } else { -++ h.next = remove(h.next, start, end); -++ } -++ int hstart = h.start.position; -++ int hend = h.end.position; -++ int s = start.position; -++ int e = end == null ? Integer.MAX_VALUE : end.position; -++ // if [hstart,hend[ and [s,e[ intervals intersect... -++ if (s < hend && e > hstart) { -++ if (s <= hstart) { -++ if (e >= hend) { -++ // [hstart,hend[ fully included in [s,e[, h removed -++ h = h.next; -++ } else { -++ // [hstart,hend[ minus [s,e[ = [e,hend[ -++ h.start = end; -++ } -++ } else if (e >= hend) { -++ // [hstart,hend[ minus [s,e[ = [hstart,s[ -++ h.end = start; -++ } else { -++ // [hstart,hend[ minus [s,e[ = [hstart,s[ + [e,hend[ -++ Handler g = new Handler(); -++ g.start = end; -++ g.end = h.end; -++ g.handler = h.handler; -++ g.desc = h.desc; -++ g.type = h.type; -++ g.next = h.next; -++ h.end = start; -++ h.next = g; -++ } -++ } -++ return h; -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/Item.java b/contrib/asm/src/org/objectweb/asm/Item.java -+new file mode 100644 -+index 0000000..917524d -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/Item.java -+@@ -0,0 +1,313 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * A constant pool item. Constant pool items can be created with the 'newXXX' -++ * methods in the {@link ClassWriter} class. -++ * -++ * @author Eric Bruneton -++ */ -++final class Item { -++ -++ /** -++ * Index of this item in the constant pool. -++ */ -++ int index; -++ -++ /** -++ * Type of this constant pool item. A single class is used to represent all -++ * constant pool item types, in order to minimize the bytecode size of this -++ * package. The value of this field is one of {@link ClassWriter#INT}, -++ * {@link ClassWriter#LONG}, {@link ClassWriter#FLOAT}, -++ * {@link ClassWriter#DOUBLE}, {@link ClassWriter#UTF8}, -++ * {@link ClassWriter#STR}, {@link ClassWriter#CLASS}, -++ * {@link ClassWriter#NAME_TYPE}, {@link ClassWriter#FIELD}, -++ * {@link ClassWriter#METH}, {@link ClassWriter#IMETH}, -++ * {@link ClassWriter#MTYPE}, {@link ClassWriter#INDY}. -++ * -++ * MethodHandle constant 9 variations are stored using a range of 9 values -++ * from {@link ClassWriter#HANDLE_BASE} + 1 to -++ * {@link ClassWriter#HANDLE_BASE} + 9. -++ * -++ * Special Item types are used for Items that are stored in the ClassWriter -++ * {@link ClassWriter#typeTable}, instead of the constant pool, in order to -++ * avoid clashes with normal constant pool items in the ClassWriter constant -++ * pool's hash table. These special item types are -++ * {@link ClassWriter#TYPE_NORMAL}, {@link ClassWriter#TYPE_UNINIT} and -++ * {@link ClassWriter#TYPE_MERGED}. -++ */ -++ int type; -++ -++ /** -++ * Value of this item, for an integer item. -++ */ -++ int intVal; -++ -++ /** -++ * Value of this item, for a long item. -++ */ -++ long longVal; -++ -++ /** -++ * First part of the value of this item, for items that do not hold a -++ * primitive value. -++ */ -++ String strVal1; -++ -++ /** -++ * Second part of the value of this item, for items that do not hold a -++ * primitive value. -++ */ -++ String strVal2; -++ -++ /** -++ * Third part of the value of this item, for items that do not hold a -++ * primitive value. -++ */ -++ String strVal3; -++ -++ /** -++ * The hash code value of this constant pool item. -++ */ -++ int hashCode; -++ -++ /** -++ * Link to another constant pool item, used for collision lists in the -++ * constant pool's hash table. -++ */ -++ Item next; -++ -++ /** -++ * Constructs an uninitialized {@link Item}. -++ */ -++ Item() { -++ } -++ -++ /** -++ * Constructs an uninitialized {@link Item} for constant pool element at -++ * given position. -++ * -++ * @param index -++ * index of the item to be constructed. -++ */ -++ Item(final int index) { -++ this.index = index; -++ } -++ -++ /** -++ * Constructs a copy of the given item. -++ * -++ * @param index -++ * index of the item to be constructed. -++ * @param i -++ * the item that must be copied into the item to be constructed. -++ */ -++ Item(final int index, final Item i) { -++ this.index = index; -++ type = i.type; -++ intVal = i.intVal; -++ longVal = i.longVal; -++ strVal1 = i.strVal1; -++ strVal2 = i.strVal2; -++ strVal3 = i.strVal3; -++ hashCode = i.hashCode; -++ } -++ -++ /** -++ * Sets this item to an integer item. -++ * -++ * @param intVal -++ * the value of this item. -++ */ -++ void set(final int intVal) { -++ this.type = ClassWriter.INT; -++ this.intVal = intVal; -++ this.hashCode = 0x7FFFFFFF & (type + intVal); -++ } -++ -++ /** -++ * Sets this item to a long item. -++ * -++ * @param longVal -++ * the value of this item. -++ */ -++ void set(final long longVal) { -++ this.type = ClassWriter.LONG; -++ this.longVal = longVal; -++ this.hashCode = 0x7FFFFFFF & (type + (int) longVal); -++ } -++ -++ /** -++ * Sets this item to a float item. -++ * -++ * @param floatVal -++ * the value of this item. -++ */ -++ void set(final float floatVal) { -++ this.type = ClassWriter.FLOAT; -++ this.intVal = Float.floatToRawIntBits(floatVal); -++ this.hashCode = 0x7FFFFFFF & (type + (int) floatVal); -++ } -++ -++ /** -++ * Sets this item to a double item. -++ * -++ * @param doubleVal -++ * the value of this item. -++ */ -++ void set(final double doubleVal) { -++ this.type = ClassWriter.DOUBLE; -++ this.longVal = Double.doubleToRawLongBits(doubleVal); -++ this.hashCode = 0x7FFFFFFF & (type + (int) doubleVal); -++ } -++ -++ /** -++ * Sets this item to an item that do not hold a primitive value. -++ * -++ * @param type -++ * the type of this item. -++ * @param strVal1 -++ * first part of the value of this item. -++ * @param strVal2 -++ * second part of the value of this item. -++ * @param strVal3 -++ * third part of the value of this item. -++ */ -++ @SuppressWarnings("fallthrough") -++ void set(final int type, final String strVal1, final String strVal2, -++ final String strVal3) { -++ this.type = type; -++ this.strVal1 = strVal1; -++ this.strVal2 = strVal2; -++ this.strVal3 = strVal3; -++ switch (type) { -++ case ClassWriter.CLASS: -++ this.intVal = 0; // intVal of a class must be zero, see visitInnerClass -++ case ClassWriter.UTF8: -++ case ClassWriter.STR: -++ case ClassWriter.MTYPE: -++ case ClassWriter.TYPE_NORMAL: -++ hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()); -++ return; -++ case ClassWriter.NAME_TYPE: { -++ hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() -++ * strVal2.hashCode()); -++ return; -++ } -++ // ClassWriter.FIELD: -++ // ClassWriter.METH: -++ // ClassWriter.IMETH: -++ // ClassWriter.HANDLE_BASE + 1..9 -++ default: -++ hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() -++ * strVal2.hashCode() * strVal3.hashCode()); -++ } -++ } -++ -++ /** -++ * Sets the item to an InvokeDynamic item. -++ * -++ * @param name -++ * invokedynamic's name. -++ * @param desc -++ * invokedynamic's desc. -++ * @param bsmIndex -++ * zero based index into the class attribute BootrapMethods. -++ */ -++ void set(String name, String desc, int bsmIndex) { -++ this.type = ClassWriter.INDY; -++ this.longVal = bsmIndex; -++ this.strVal1 = name; -++ this.strVal2 = desc; -++ this.hashCode = 0x7FFFFFFF & (ClassWriter.INDY + bsmIndex -++ * strVal1.hashCode() * strVal2.hashCode()); -++ } -++ -++ /** -++ * Sets the item to a BootstrapMethod item. -++ * -++ * @param position -++ * position in byte in the class attribute BootrapMethods. -++ * @param hashCode -++ * hashcode of the item. This hashcode is processed from the -++ * hashcode of the bootstrap method and the hashcode of all -++ * bootstrap arguments. -++ */ -++ void set(int position, int hashCode) { -++ this.type = ClassWriter.BSM; -++ this.intVal = position; -++ this.hashCode = hashCode; -++ } -++ -++ /** -++ * Indicates if the given item is equal to this one. <i>This method assumes -++ * that the two items have the same {@link #type}</i>. -++ * -++ * @param i -++ * the item to be compared to this one. Both items must have the -++ * same {@link #type}. -++ * @return <tt>true</tt> if the given item if equal to this one, -++ * <tt>false</tt> otherwise. -++ */ -++ boolean isEqualTo(final Item i) { -++ switch (type) { -++ case ClassWriter.UTF8: -++ case ClassWriter.STR: -++ case ClassWriter.CLASS: -++ case ClassWriter.MTYPE: -++ case ClassWriter.TYPE_NORMAL: -++ return i.strVal1.equals(strVal1); -++ case ClassWriter.TYPE_MERGED: -++ case ClassWriter.LONG: -++ case ClassWriter.DOUBLE: -++ return i.longVal == longVal; -++ case ClassWriter.INT: -++ case ClassWriter.FLOAT: -++ return i.intVal == intVal; -++ case ClassWriter.TYPE_UNINIT: -++ return i.intVal == intVal && i.strVal1.equals(strVal1); -++ case ClassWriter.NAME_TYPE: -++ return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2); -++ case ClassWriter.INDY: { -++ return i.longVal == longVal && i.strVal1.equals(strVal1) -++ && i.strVal2.equals(strVal2); -++ } -++ // case ClassWriter.FIELD: -++ // case ClassWriter.METH: -++ // case ClassWriter.IMETH: -++ // case ClassWriter.HANDLE_BASE + 1..9 -++ default: -++ return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2) -++ && i.strVal3.equals(strVal3); -++ } -++ } -++ -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/Label.java b/contrib/asm/src/org/objectweb/asm/Label.java -+new file mode 100644 -+index 0000000..6bca6fb -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/Label.java -+@@ -0,0 +1,565 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * A label represents a position in the bytecode of a method. Labels are used -++ * for jump, goto, and switch instructions, and for try catch blocks. A label -++ * designates the <i>instruction</i> that is just after. Note however that there -++ * can be other elements between a label and the instruction it designates (such -++ * as other labels, stack map frames, line numbers, etc.). -++ * -++ * @author Eric Bruneton -++ */ -++public class Label { -++ -++ /** -++ * Indicates if this label is only used for debug attributes. Such a label -++ * is not the start of a basic block, the target of a jump instruction, or -++ * an exception handler. It can be safely ignored in control flow graph -++ * analysis algorithms (for optimization purposes). -++ */ -++ static final int DEBUG = 1; -++ -++ /** -++ * Indicates if the position of this label is known. -++ */ -++ static final int RESOLVED = 2; -++ -++ /** -++ * Indicates if this label has been updated, after instruction resizing. -++ */ -++ static final int RESIZED = 4; -++ -++ /** -++ * Indicates if this basic block has been pushed in the basic block stack. -++ * See {@link MethodWriter#visitMaxs visitMaxs}. -++ */ -++ static final int PUSHED = 8; -++ -++ /** -++ * Indicates if this label is the target of a jump instruction, or the start -++ * of an exception handler. -++ */ -++ static final int TARGET = 16; -++ -++ /** -++ * Indicates if a stack map frame must be stored for this label. -++ */ -++ static final int STORE = 32; -++ -++ /** -++ * Indicates if this label corresponds to a reachable basic block. -++ */ -++ static final int REACHABLE = 64; -++ -++ /** -++ * Indicates if this basic block ends with a JSR instruction. -++ */ -++ static final int JSR = 128; -++ -++ /** -++ * Indicates if this basic block ends with a RET instruction. -++ */ -++ static final int RET = 256; -++ -++ /** -++ * Indicates if this basic block is the start of a subroutine. -++ */ -++ static final int SUBROUTINE = 512; -++ -++ /** -++ * Indicates if this subroutine basic block has been visited by a -++ * visitSubroutine(null, ...) call. -++ */ -++ static final int VISITED = 1024; -++ -++ /** -++ * Indicates if this subroutine basic block has been visited by a -++ * visitSubroutine(!null, ...) call. -++ */ -++ static final int VISITED2 = 2048; -++ -++ /** -++ * Field used to associate user information to a label. Warning: this field -++ * is used by the ASM tree package. In order to use it with the ASM tree -++ * package you must override the -++ * {@link org.objectweb.asm.tree.MethodNode#getLabelNode} method. -++ */ -++ public Object info; -++ -++ /** -++ * Flags that indicate the status of this label. -++ * -++ * @see #DEBUG -++ * @see #RESOLVED -++ * @see #RESIZED -++ * @see #PUSHED -++ * @see #TARGET -++ * @see #STORE -++ * @see #REACHABLE -++ * @see #JSR -++ * @see #RET -++ */ -++ int status; -++ -++ /** -++ * The line number corresponding to this label, if known. If there are -++ * several lines, each line is stored in a separate label, all linked via -++ * their next field (these links are created in ClassReader and removed just -++ * before visitLabel is called, so that this does not impact the rest of the -++ * code). -++ */ -++ int line; -++ -++ /** -++ * The position of this label in the code, if known. -++ */ -++ int position; -++ -++ /** -++ * Number of forward references to this label, times two. -++ */ -++ private int referenceCount; -++ -++ /** -++ * Informations about forward references. Each forward reference is -++ * described by two consecutive integers in this array: the first one is the -++ * position of the first byte of the bytecode instruction that contains the -++ * forward reference, while the second is the position of the first byte of -++ * the forward reference itself. In fact the sign of the first integer -++ * indicates if this reference uses 2 or 4 bytes, and its absolute value -++ * gives the position of the bytecode instruction. This array is also used -++ * as a bitset to store the subroutines to which a basic block belongs. This -++ * information is needed in {@linked MethodWriter#visitMaxs}, after all -++ * forward references have been resolved. Hence the same array can be used -++ * for both purposes without problems. -++ */ -++ private int[] srcAndRefPositions; -++ -++ // ------------------------------------------------------------------------ -++ -++ /* -++ * Fields for the control flow and data flow graph analysis algorithms (used -++ * to compute the maximum stack size or the stack map frames). A control -++ * flow graph contains one node per "basic block", and one edge per "jump" -++ * from one basic block to another. Each node (i.e., each basic block) is -++ * represented by the Label object that corresponds to the first instruction -++ * of this basic block. Each node also stores the list of its successors in -++ * the graph, as a linked list of Edge objects. -++ * -++ * The control flow analysis algorithms used to compute the maximum stack -++ * size or the stack map frames are similar and use two steps. The first -++ * step, during the visit of each instruction, builds information about the -++ * state of the local variables and the operand stack at the end of each -++ * basic block, called the "output frame", <i>relatively</i> to the frame -++ * state at the beginning of the basic block, which is called the "input -++ * frame", and which is <i>unknown</i> during this step. The second step, in -++ * {@link MethodWriter#visitMaxs}, is a fix point algorithm that computes -++ * information about the input frame of each basic block, from the input -++ * state of the first basic block (known from the method signature), and by -++ * the using the previously computed relative output frames. -++ * -++ * The algorithm used to compute the maximum stack size only computes the -++ * relative output and absolute input stack heights, while the algorithm -++ * used to compute stack map frames computes relative output frames and -++ * absolute input frames. -++ */ -++ -++ /** -++ * Start of the output stack relatively to the input stack. The exact -++ * semantics of this field depends on the algorithm that is used. -++ * -++ * When only the maximum stack size is computed, this field is the number of -++ * elements in the input stack. -++ * -++ * When the stack map frames are completely computed, this field is the -++ * offset of the first output stack element relatively to the top of the -++ * input stack. This offset is always negative or null. A null offset means -++ * that the output stack must be appended to the input stack. A -n offset -++ * means that the first n output stack elements must replace the top n input -++ * stack elements, and that the other elements must be appended to the input -++ * stack. -++ */ -++ int inputStackTop; -++ -++ /** -++ * Maximum height reached by the output stack, relatively to the top of the -++ * input stack. This maximum is always positive or null. -++ */ -++ int outputStackMax; -++ -++ /** -++ * Information about the input and output stack map frames of this basic -++ * block. This field is only used when {@link ClassWriter#COMPUTE_FRAMES} -++ * option is used. -++ */ -++ Frame frame; -++ -++ /** -++ * The successor of this label, in the order they are visited. This linked -++ * list does not include labels used for debug info only. If -++ * {@link ClassWriter#COMPUTE_FRAMES} option is used then, in addition, it -++ * does not contain successive labels that denote the same bytecode position -++ * (in this case only the first label appears in this list). -++ */ -++ Label successor; -++ -++ /** -++ * The successors of this node in the control flow graph. These successors -++ * are stored in a linked list of {@link Edge Edge} objects, linked to each -++ * other by their {@link Edge#next} field. -++ */ -++ Edge successors; -++ -++ /** -++ * The next basic block in the basic block stack. This stack is used in the -++ * main loop of the fix point algorithm used in the second step of the -++ * control flow analysis algorithms. It is also used in -++ * {@link #visitSubroutine} to avoid using a recursive method, and in -++ * ClassReader to temporarily store multiple source lines for a label. -++ * -++ * @see MethodWriter#visitMaxs -++ */ -++ Label next; -++ -++ // ------------------------------------------------------------------------ -++ // Constructor -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Constructs a new label. -++ */ -++ public Label() { -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Methods to compute offsets and to manage forward references -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Returns the offset corresponding to this label. This offset is computed -++ * from the start of the method's bytecode. <i>This method is intended for -++ * {@link Attribute} sub classes, and is normally not needed by class -++ * generators or adapters.</i> -++ * -++ * @return the offset corresponding to this label. -++ * @throws IllegalStateException -++ * if this label is not resolved yet. -++ */ -++ public int getOffset() { -++ if ((status & RESOLVED) == 0) { -++ throw new IllegalStateException( -++ "Label offset position has not been resolved yet"); -++ } -++ return position; -++ } -++ -++ /** -++ * Puts a reference to this label in the bytecode of a method. If the -++ * position of the label is known, the offset is computed and written -++ * directly. Otherwise, a null offset is written and a new forward reference -++ * is declared for this label. -++ * -++ * @param owner -++ * the code writer that calls this method. -++ * @param out -++ * the bytecode of the method. -++ * @param source -++ * the position of first byte of the bytecode instruction that -++ * contains this label. -++ * @param wideOffset -++ * <tt>true</tt> if the reference must be stored in 4 bytes, or -++ * <tt>false</tt> if it must be stored with 2 bytes. -++ * @throws IllegalArgumentException -++ * if this label has not been created by the given code writer. -++ */ -++ void put(final MethodWriter owner, final ByteVector out, final int source, -++ final boolean wideOffset) { -++ if ((status & RESOLVED) == 0) { -++ if (wideOffset) { -++ addReference(-1 - source, out.length); -++ out.putInt(-1); -++ } else { -++ addReference(source, out.length); -++ out.putShort(-1); -++ } -++ } else { -++ if (wideOffset) { -++ out.putInt(position - source); -++ } else { -++ out.putShort(position - source); -++ } -++ } -++ } -++ -++ /** -++ * Adds a forward reference to this label. This method must be called only -++ * for a true forward reference, i.e. only if this label is not resolved -++ * yet. For backward references, the offset of the reference can be, and -++ * must be, computed and stored directly. -++ * -++ * @param sourcePosition -++ * the position of the referencing instruction. This position -++ * will be used to compute the offset of this forward reference. -++ * @param referencePosition -++ * the position where the offset for this forward reference must -++ * be stored. -++ */ -++ private void addReference(final int sourcePosition, -++ final int referencePosition) { -++ if (srcAndRefPositions == null) { -++ srcAndRefPositions = new int[6]; -++ } -++ if (referenceCount >= srcAndRefPositions.length) { -++ int[] a = new int[srcAndRefPositions.length + 6]; -++ System.arraycopy(srcAndRefPositions, 0, a, 0, -++ srcAndRefPositions.length); -++ srcAndRefPositions = a; -++ } -++ srcAndRefPositions[referenceCount++] = sourcePosition; -++ srcAndRefPositions[referenceCount++] = referencePosition; -++ } -++ -++ /** -++ * Resolves all forward references to this label. This method must be called -++ * when this label is added to the bytecode of the method, i.e. when its -++ * position becomes known. This method fills in the blanks that where left -++ * in the bytecode by each forward reference previously added to this label. -++ * -++ * @param owner -++ * the code writer that calls this method. -++ * @param position -++ * the position of this label in the bytecode. -++ * @param data -++ * the bytecode of the method. -++ * @return <tt>true</tt> if a blank that was left for this label was to -++ * small to store the offset. In such a case the corresponding jump -++ * instruction is replaced with a pseudo instruction (using unused -++ * opcodes) using an unsigned two bytes offset. These pseudo -++ * instructions will need to be replaced with true instructions with -++ * wider offsets (4 bytes instead of 2). This is done in -++ * {@link MethodWriter#resizeInstructions}. -++ * @throws IllegalArgumentException -++ * if this label has already been resolved, or if it has not -++ * been created by the given code writer. -++ */ -++ boolean resolve(final MethodWriter owner, final int position, -++ final byte[] data) { -++ boolean needUpdate = false; -++ this.status |= RESOLVED; -++ this.position = position; -++ int i = 0; -++ while (i < referenceCount) { -++ int source = srcAndRefPositions[i++]; -++ int reference = srcAndRefPositions[i++]; -++ int offset; -++ if (source >= 0) { -++ offset = position - source; -++ if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) { -++ /* -++ * changes the opcode of the jump instruction, in order to -++ * be able to find it later (see resizeInstructions in -++ * MethodWriter). These temporary opcodes are similar to -++ * jump instruction opcodes, except that the 2 bytes offset -++ * is unsigned (and can therefore represent values from 0 to -++ * 65535, which is sufficient since the size of a method is -++ * limited to 65535 bytes). -++ */ -++ int opcode = data[reference - 1] & 0xFF; -++ if (opcode <= Opcodes.JSR) { -++ // changes IFEQ ... JSR to opcodes 202 to 217 -++ data[reference - 1] = (byte) (opcode + 49); -++ } else { -++ // changes IFNULL and IFNONNULL to opcodes 218 and 219 -++ data[reference - 1] = (byte) (opcode + 20); -++ } -++ needUpdate = true; -++ } -++ data[reference++] = (byte) (offset >>> 8); -++ data[reference] = (byte) offset; -++ } else { -++ offset = position + source + 1; -++ data[reference++] = (byte) (offset >>> 24); -++ data[reference++] = (byte) (offset >>> 16); -++ data[reference++] = (byte) (offset >>> 8); -++ data[reference] = (byte) offset; -++ } -++ } -++ return needUpdate; -++ } -++ -++ /** -++ * Returns the first label of the series to which this label belongs. For an -++ * isolated label or for the first label in a series of successive labels, -++ * this method returns the label itself. For other labels it returns the -++ * first label of the series. -++ * -++ * @return the first label of the series to which this label belongs. -++ */ -++ Label getFirst() { -++ return !ClassReader.FRAMES || frame == null ? this : frame.owner; -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Methods related to subroutines -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Returns true is this basic block belongs to the given subroutine. -++ * -++ * @param id -++ * a subroutine id. -++ * @return true is this basic block belongs to the given subroutine. -++ */ -++ boolean inSubroutine(final long id) { -++ if ((status & Label.VISITED) != 0) { -++ return (srcAndRefPositions[(int) (id >>> 32)] & (int) id) != 0; -++ } -++ return false; -++ } -++ -++ /** -++ * Returns true if this basic block and the given one belong to a common -++ * subroutine. -++ * -++ * @param block -++ * another basic block. -++ * @return true if this basic block and the given one belong to a common -++ * subroutine. -++ */ -++ boolean inSameSubroutine(final Label block) { -++ if ((status & VISITED) == 0 || (block.status & VISITED) == 0) { -++ return false; -++ } -++ for (int i = 0; i < srcAndRefPositions.length; ++i) { -++ if ((srcAndRefPositions[i] & block.srcAndRefPositions[i]) != 0) { -++ return true; -++ } -++ } -++ return false; -++ } -++ -++ /** -++ * Marks this basic block as belonging to the given subroutine. -++ * -++ * @param id -++ * a subroutine id. -++ * @param nbSubroutines -++ * the total number of subroutines in the method. -++ */ -++ void addToSubroutine(final long id, final int nbSubroutines) { -++ if ((status & VISITED) == 0) { -++ status |= VISITED; -++ srcAndRefPositions = new int[nbSubroutines / 32 + 1]; -++ } -++ srcAndRefPositions[(int) (id >>> 32)] |= (int) id; -++ } -++ -++ /** -++ * Finds the basic blocks that belong to a given subroutine, and marks these -++ * blocks as belonging to this subroutine. This method follows the control -++ * flow graph to find all the blocks that are reachable from the current -++ * block WITHOUT following any JSR target. -++ * -++ * @param JSR -++ * a JSR block that jumps to this subroutine. If this JSR is not -++ * null it is added to the successor of the RET blocks found in -++ * the subroutine. -++ * @param id -++ * the id of this subroutine. -++ * @param nbSubroutines -++ * the total number of subroutines in the method. -++ */ -++ void visitSubroutine(final Label JSR, final long id, final int nbSubroutines) { -++ // user managed stack of labels, to avoid using a recursive method -++ // (recursivity can lead to stack overflow with very large methods) -++ Label stack = this; -++ while (stack != null) { -++ // removes a label l from the stack -++ Label l = stack; -++ stack = l.next; -++ l.next = null; -++ -++ if (JSR != null) { -++ if ((l.status & VISITED2) != 0) { -++ continue; -++ } -++ l.status |= VISITED2; -++ // adds JSR to the successors of l, if it is a RET block -++ if ((l.status & RET) != 0) { -++ if (!l.inSameSubroutine(JSR)) { -++ Edge e = new Edge(); -++ e.info = l.inputStackTop; -++ e.successor = JSR.successors.successor; -++ e.next = l.successors; -++ l.successors = e; -++ } -++ } -++ } else { -++ // if the l block already belongs to subroutine 'id', continue -++ if (l.inSubroutine(id)) { -++ continue; -++ } -++ // marks the l block as belonging to subroutine 'id' -++ l.addToSubroutine(id, nbSubroutines); -++ } -++ // pushes each successor of l on the stack, except JSR targets -++ Edge e = l.successors; -++ while (e != null) { -++ // if the l block is a JSR block, then 'l.successors.next' leads -++ // to the JSR target (see {@link #visitJumpInsn}) and must -++ // therefore not be followed -++ if ((l.status & Label.JSR) == 0 || e != l.successors.next) { -++ // pushes e.successor on the stack if it not already added -++ if (e.successor.next == null) { -++ e.successor.next = stack; -++ stack = e.successor; -++ } -++ } -++ e = e.next; -++ } -++ } -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Overriden Object methods -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Returns a string representation of this label. -++ * -++ * @return a string representation of this label. -++ */ -++ @Override -++ public String toString() { -++ return "L" + System.identityHashCode(this); -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/MethodVisitor.java b/contrib/asm/src/org/objectweb/asm/MethodVisitor.java -+new file mode 100644 -+index 0000000..f0927e8 -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/MethodVisitor.java -+@@ -0,0 +1,881 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * A visitor to visit a Java method. The methods of this class must be called in -++ * the following order: ( <tt>visitParameter</tt> )* [ -++ * <tt>visitAnnotationDefault</tt> ] ( <tt>visitAnnotation</tt> | -++ * <tt>visitParameterAnnotation</tt> <tt>visitTypeAnnotation</tt> | -++ * <tt>visitAttribute</tt> )* [ <tt>visitCode</tt> ( <tt>visitFrame</tt> | -++ * <tt>visit<i>X</i>Insn</tt> | <tt>visitLabel</tt> | -++ * <tt>visitInsnAnnotation</tt> | <tt>visitTryCatchBlock</tt> | -++ * <tt>visitTryCatchAnnotation</tt> | <tt>visitLocalVariable</tt> | -++ * <tt>visitLocalVariableAnnotation</tt> | <tt>visitLineNumber</tt> )* -++ * <tt>visitMaxs</tt> ] <tt>visitEnd</tt>. In addition, the -++ * <tt>visit<i>X</i>Insn</tt> and <tt>visitLabel</tt> methods must be called in -++ * the sequential order of the bytecode instructions of the visited code, -++ * <tt>visitInsnAnnotation</tt> must be called <i>after</i> the annotated -++ * instruction, <tt>visitTryCatchBlock</tt> must be called <i>before</i> the -++ * labels passed as arguments have been visited, -++ * <tt>visitTryCatchBlockAnnotation</tt> must be called <i>after</i> the -++ * corresponding try catch block has been visited, and the -++ * <tt>visitLocalVariable</tt>, <tt>visitLocalVariableAnnotation</tt> and -++ * <tt>visitLineNumber</tt> methods must be called <i>after</i> the labels -++ * passed as arguments have been visited. -++ * -++ * @author Eric Bruneton -++ */ -++public abstract class MethodVisitor { -++ -++ /** -++ * The ASM API version implemented by this visitor. The value of this field -++ * must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -++ */ -++ protected final int api; -++ -++ /** -++ * The method visitor to which this visitor must delegate method calls. May -++ * be null. -++ */ -++ protected MethodVisitor mv; -++ -++ /** -++ * Constructs a new {@link MethodVisitor}. -++ * -++ * @param api -++ * the ASM API version implemented by this visitor. Must be one -++ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -++ */ -++ public MethodVisitor(final int api) { -++ this(api, null); -++ } -++ -++ /** -++ * Constructs a new {@link MethodVisitor}. -++ * -++ * @param api -++ * the ASM API version implemented by this visitor. Must be one -++ * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. -++ * @param mv -++ * the method visitor to which this visitor must delegate method -++ * calls. May be null. -++ */ -++ public MethodVisitor(final int api, final MethodVisitor mv) { -++ if (api != Opcodes.ASM4 && api != Opcodes.ASM5) { -++ throw new IllegalArgumentException(); -++ } -++ this.api = api; -++ this.mv = mv; -++ } -++ -++ // ------------------------------------------------------------------------- -++ // Parameters, annotations and non standard attributes -++ // ------------------------------------------------------------------------- -++ -++ /** -++ * Visits a parameter of this method. -++ * -++ * @param name -++ * parameter name or null if none is provided. -++ * @param access -++ * the parameter's access flags, only <tt>ACC_FINAL</tt>, -++ * <tt>ACC_SYNTHETIC</tt> or/and <tt>ACC_MANDATED</tt> are -++ * allowed (see {@link Opcodes}). -++ */ -++ public void visitParameter(String name, int access) { -++ if (api < Opcodes.ASM5) { -++ throw new RuntimeException(); -++ } -++ if (mv != null) { -++ mv.visitParameter(name, access); -++ } -++ } -++ -++ /** -++ * Visits the default value of this annotation interface method. -++ * -++ * @return a visitor to the visit the actual default value of this -++ * annotation interface method, or <tt>null</tt> if this visitor is -++ * not interested in visiting this default value. The 'name' -++ * parameters passed to the methods of this annotation visitor are -++ * ignored. Moreover, exacly one visit method must be called on this -++ * annotation visitor, followed by visitEnd. -++ */ -++ public AnnotationVisitor visitAnnotationDefault() { -++ if (mv != null) { -++ return mv.visitAnnotationDefault(); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits an annotation of this method. -++ * -++ * @param desc -++ * the class descriptor of the annotation class. -++ * @param visible -++ * <tt>true</tt> if the annotation is visible at runtime. -++ * @return a visitor to visit the annotation values, or <tt>null</tt> if -++ * this visitor is not interested in visiting this annotation. -++ */ -++ public AnnotationVisitor visitAnnotation(String desc, boolean visible) { -++ if (mv != null) { -++ return mv.visitAnnotation(desc, visible); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits an annotation on a type in the method signature. -++ * -++ * @param typeRef -++ * a reference to the annotated type. The sort of this type -++ * reference must be {@link TypeReference#METHOD_TYPE_PARAMETER -++ * METHOD_TYPE_PARAMETER}, -++ * {@link TypeReference#METHOD_TYPE_PARAMETER_BOUND -++ * METHOD_TYPE_PARAMETER_BOUND}, -++ * {@link TypeReference#METHOD_RETURN METHOD_RETURN}, -++ * {@link TypeReference#METHOD_RECEIVER METHOD_RECEIVER}, -++ * {@link TypeReference#METHOD_FORMAL_PARAMETER -++ * METHOD_FORMAL_PARAMETER} or {@link TypeReference#THROWS -++ * THROWS}. See {@link TypeReference}. -++ * @param typePath -++ * the path to the annotated type argument, wildcard bound, array -++ * element type, or static inner type within 'typeRef'. May be -++ * <tt>null</tt> if the annotation targets 'typeRef' as a whole. -++ * @param desc -++ * the class descriptor of the annotation class. -++ * @param visible -++ * <tt>true</tt> if the annotation is visible at runtime. -++ * @return a visitor to visit the annotation values, or <tt>null</tt> if -++ * this visitor is not interested in visiting this annotation. -++ */ -++ public AnnotationVisitor visitTypeAnnotation(int typeRef, -++ TypePath typePath, String desc, boolean visible) { -++ if (api < Opcodes.ASM5) { -++ throw new RuntimeException(); -++ } -++ if (mv != null) { -++ return mv.visitTypeAnnotation(typeRef, typePath, desc, visible); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits an annotation of a parameter this method. -++ * -++ * @param parameter -++ * the parameter index. -++ * @param desc -++ * the class descriptor of the annotation class. -++ * @param visible -++ * <tt>true</tt> if the annotation is visible at runtime. -++ * @return a visitor to visit the annotation values, or <tt>null</tt> if -++ * this visitor is not interested in visiting this annotation. -++ */ -++ public AnnotationVisitor visitParameterAnnotation(int parameter, -++ String desc, boolean visible) { -++ if (mv != null) { -++ return mv.visitParameterAnnotation(parameter, desc, visible); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits a non standard attribute of this method. -++ * -++ * @param attr -++ * an attribute. -++ */ -++ public void visitAttribute(Attribute attr) { -++ if (mv != null) { -++ mv.visitAttribute(attr); -++ } -++ } -++ -++ /** -++ * Starts the visit of the method's code, if any (i.e. non abstract method). -++ */ -++ public void visitCode() { -++ if (mv != null) { -++ mv.visitCode(); -++ } -++ } -++ -++ /** -++ * Visits the current state of the local variables and operand stack -++ * elements. This method must(*) be called <i>just before</i> any -++ * instruction <b>i</b> that follows an unconditional branch instruction -++ * such as GOTO or THROW, that is the target of a jump instruction, or that -++ * starts an exception handler block. The visited types must describe the -++ * values of the local variables and of the operand stack elements <i>just -++ * before</i> <b>i</b> is executed.<br> -++ * <br> -++ * (*) this is mandatory only for classes whose version is greater than or -++ * equal to {@link Opcodes#V1_6 V1_6}. <br> -++ * <br> -++ * The frames of a method must be given either in expanded form, or in -++ * compressed form (all frames must use the same format, i.e. you must not -++ * mix expanded and compressed frames within a single method): -++ * <ul> -++ * <li>In expanded form, all frames must have the F_NEW type.</li> -++ * <li>In compressed form, frames are basically "deltas" from the state of -++ * the previous frame: -++ * <ul> -++ * <li>{@link Opcodes#F_SAME} representing frame with exactly the same -++ * locals as the previous frame and with the empty stack.</li> -++ * <li>{@link Opcodes#F_SAME1} representing frame with exactly the same -++ * locals as the previous frame and with single value on the stack ( -++ * <code>nStack</code> is 1 and <code>stack[0]</code> contains value for the -++ * type of the stack item).</li> -++ * <li>{@link Opcodes#F_APPEND} representing frame with current locals are -++ * the same as the locals in the previous frame, except that additional -++ * locals are defined (<code>nLocal</code> is 1, 2 or 3 and -++ * <code>local</code> elements contains values representing added types).</li> -++ * <li>{@link Opcodes#F_CHOP} representing frame with current locals are the -++ * same as the locals in the previous frame, except that the last 1-3 locals -++ * are absent and with the empty stack (<code>nLocals</code> is 1, 2 or 3).</li> -++ * <li>{@link Opcodes#F_FULL} representing complete frame data.</li> -++ * </ul> -++ * </li> -++ * </ul> -++ * <br> -++ * In both cases the first frame, corresponding to the method's parameters -++ * and access flags, is implicit and must not be visited. Also, it is -++ * illegal to visit two or more frames for the same code location (i.e., at -++ * least one instruction must be visited between two calls to visitFrame). -++ * -++ * @param type -++ * the type of this stack map frame. Must be -++ * {@link Opcodes#F_NEW} for expanded frames, or -++ * {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, -++ * {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or -++ * {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for -++ * compressed frames. -++ * @param nLocal -++ * the number of local variables in the visited frame. -++ * @param local -++ * the local variable types in this frame. This array must not be -++ * modified. Primitive types are represented by -++ * {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, -++ * {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, -++ * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or -++ * {@link Opcodes#UNINITIALIZED_THIS} (long and double are -++ * represented by a single element). Reference types are -++ * represented by String objects (representing internal names), -++ * and uninitialized types by Label objects (this label -++ * designates the NEW instruction that created this uninitialized -++ * value). -++ * @param nStack -++ * the number of operand stack elements in the visited frame. -++ * @param stack -++ * the operand stack types in this frame. This array must not be -++ * modified. Its content has the same format as the "local" -++ * array. -++ * @throws IllegalStateException -++ * if a frame is visited just after another one, without any -++ * instruction between the two (unless this frame is a -++ * Opcodes#F_SAME frame, in which case it is silently ignored). -++ */ -++ public void visitFrame(int type, int nLocal, Object[] local, int nStack, -++ Object[] stack) { -++ if (mv != null) { -++ mv.visitFrame(type, nLocal, local, nStack, stack); -++ } -++ } -++ -++ // ------------------------------------------------------------------------- -++ // Normal instructions -++ // ------------------------------------------------------------------------- -++ -++ /** -++ * Visits a zero operand instruction. -++ * -++ * @param opcode -++ * the opcode of the instruction to be visited. This opcode is -++ * either NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, -++ * ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1, -++ * FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD, -++ * LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, -++ * IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, -++ * SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, -++ * DUP2_X2, SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, -++ * IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM, LREM, -++ * FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR, -++ * IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D, -++ * L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S, -++ * LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN, -++ * DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, -++ * or MONITOREXIT. -++ */ -++ public void visitInsn(int opcode) { -++ if (mv != null) { -++ mv.visitInsn(opcode); -++ } -++ } -++ -++ /** -++ * Visits an instruction with a single int operand. -++ * -++ * @param opcode -++ * the opcode of the instruction to be visited. This opcode is -++ * either BIPUSH, SIPUSH or NEWARRAY. -++ * @param operand -++ * the operand of the instruction to be visited.<br> -++ * When opcode is BIPUSH, operand value should be between -++ * Byte.MIN_VALUE and Byte.MAX_VALUE.<br> -++ * When opcode is SIPUSH, operand value should be between -++ * Short.MIN_VALUE and Short.MAX_VALUE.<br> -++ * When opcode is NEWARRAY, operand value should be one of -++ * {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR}, -++ * {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE}, -++ * {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT}, -++ * {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}. -++ */ -++ public void visitIntInsn(int opcode, int operand) { -++ if (mv != null) { -++ mv.visitIntInsn(opcode, operand); -++ } -++ } -++ -++ /** -++ * Visits a local variable instruction. A local variable instruction is an -++ * instruction that loads or stores the value of a local variable. -++ * -++ * @param opcode -++ * the opcode of the local variable instruction to be visited. -++ * This opcode is either ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, -++ * ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET. -++ * @param var -++ * the operand of the instruction to be visited. This operand is -++ * the index of a local variable. -++ */ -++ public void visitVarInsn(int opcode, int var) { -++ if (mv != null) { -++ mv.visitVarInsn(opcode, var); -++ } -++ } -++ -++ /** -++ * Visits a type instruction. A type instruction is an instruction that -++ * takes the internal name of a class as parameter. -++ * -++ * @param opcode -++ * the opcode of the type instruction to be visited. This opcode -++ * is either NEW, ANEWARRAY, CHECKCAST or INSTANCEOF. -++ * @param type -++ * the operand of the instruction to be visited. This operand -++ * must be the internal name of an object or array class (see -++ * {@link Type#getInternalName() getInternalName}). -++ */ -++ public void visitTypeInsn(int opcode, String type) { -++ if (mv != null) { -++ mv.visitTypeInsn(opcode, type); -++ } -++ } -++ -++ /** -++ * Visits a field instruction. A field instruction is an instruction that -++ * loads or stores the value of a field of an object. -++ * -++ * @param opcode -++ * the opcode of the type instruction to be visited. This opcode -++ * is either GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD. -++ * @param owner -++ * the internal name of the field's owner class (see -++ * {@link Type#getInternalName() getInternalName}). -++ * @param name -++ * the field's name. -++ * @param desc -++ * the field's descriptor (see {@link Type Type}). -++ */ -++ public void visitFieldInsn(int opcode, String owner, String name, -++ String desc) { -++ if (mv != null) { -++ mv.visitFieldInsn(opcode, owner, name, desc); -++ } -++ } -++ -++ /** -++ * Visits a method instruction. A method instruction is an instruction that -++ * invokes a method. -++ * -++ * @param opcode -++ * the opcode of the type instruction to be visited. This opcode -++ * is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or -++ * INVOKEINTERFACE. -++ * @param owner -++ * the internal name of the method's owner class (see -++ * {@link Type#getInternalName() getInternalName}). -++ * @param name -++ * the method's name. -++ * @param desc -++ * the method's descriptor (see {@link Type Type}). -++ */ -++ @Deprecated -++ public void visitMethodInsn(int opcode, String owner, String name, -++ String desc) { -++ if (api >= Opcodes.ASM5) { -++ boolean itf = opcode == Opcodes.INVOKEINTERFACE; -++ visitMethodInsn(opcode, owner, name, desc, itf); -++ return; -++ } -++ if (mv != null) { -++ mv.visitMethodInsn(opcode, owner, name, desc); -++ } -++ } -++ -++ /** -++ * Visits a method instruction. A method instruction is an instruction that -++ * invokes a method. -++ * -++ * @param opcode -++ * the opcode of the type instruction to be visited. This opcode -++ * is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or -++ * INVOKEINTERFACE. -++ * @param owner -++ * the internal name of the method's owner class (see -++ * {@link Type#getInternalName() getInternalName}). -++ * @param name -++ * the method's name. -++ * @param desc -++ * the method's descriptor (see {@link Type Type}). -++ * @param itf -++ * if the method's owner class is an interface. -++ */ -++ public void visitMethodInsn(int opcode, String owner, String name, -++ String desc, boolean itf) { -++ if (api < Opcodes.ASM5) { -++ if (itf != (opcode == Opcodes.INVOKEINTERFACE)) { -++ throw new IllegalArgumentException( -++ "INVOKESPECIAL/STATIC on interfaces require ASM 5"); -++ } -++ visitMethodInsn(opcode, owner, name, desc); -++ return; -++ } -++ if (mv != null) { -++ mv.visitMethodInsn(opcode, owner, name, desc, itf); -++ } -++ } -++ -++ /** -++ * Visits an invokedynamic instruction. -++ * -++ * @param name -++ * the method's name. -++ * @param desc -++ * the method's descriptor (see {@link Type Type}). -++ * @param bsm -++ * the bootstrap method. -++ * @param bsmArgs -++ * the bootstrap method constant arguments. Each argument must be -++ * an {@link Integer}, {@link Float}, {@link Long}, -++ * {@link Double}, {@link String}, {@link Type} or {@link Handle} -++ * value. This method is allowed to modify the content of the -++ * array so a caller should expect that this array may change. -++ */ -++ public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, -++ Object... bsmArgs) { -++ if (mv != null) { -++ mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); -++ } -++ } -++ -++ /** -++ * Visits a jump instruction. A jump instruction is an instruction that may -++ * jump to another instruction. -++ * -++ * @param opcode -++ * the opcode of the type instruction to be visited. This opcode -++ * is either IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, -++ * IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, -++ * IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL. -++ * @param label -++ * the operand of the instruction to be visited. This operand is -++ * a label that designates the instruction to which the jump -++ * instruction may jump. -++ */ -++ public void visitJumpInsn(int opcode, Label label) { -++ if (mv != null) { -++ mv.visitJumpInsn(opcode, label); -++ } -++ } -++ -++ /** -++ * Visits a label. A label designates the instruction that will be visited -++ * just after it. -++ * -++ * @param label -++ * a {@link Label Label} object. -++ */ -++ public void visitLabel(Label label) { -++ if (mv != null) { -++ mv.visitLabel(label); -++ } -++ } -++ -++ // ------------------------------------------------------------------------- -++ // Special instructions -++ // ------------------------------------------------------------------------- -++ -++ /** -++ * Visits a LDC instruction. Note that new constant types may be added in -++ * future versions of the Java Virtual Machine. To easily detect new -++ * constant types, implementations of this method should check for -++ * unexpected constant types, like this: -++ * -++ * <pre> -++ * if (cst instanceof Integer) { -++ * // ... -++ * } else if (cst instanceof Float) { -++ * // ... -++ * } else if (cst instanceof Long) { -++ * // ... -++ * } else if (cst instanceof Double) { -++ * // ... -++ * } else if (cst instanceof String) { -++ * // ... -++ * } else if (cst instanceof Type) { -++ * int sort = ((Type) cst).getSort(); -++ * if (sort == Type.OBJECT) { -++ * // ... -++ * } else if (sort == Type.ARRAY) { -++ * // ... -++ * } else if (sort == Type.METHOD) { -++ * // ... -++ * } else { -++ * // throw an exception -++ * } -++ * } else if (cst instanceof Handle) { -++ * // ... -++ * } else { -++ * // throw an exception -++ * } -++ * </pre> -++ * -++ * @param cst -++ * the constant to be loaded on the stack. This parameter must be -++ * a non null {@link Integer}, a {@link Float}, a {@link Long}, a -++ * {@link Double}, a {@link String}, a {@link Type} of OBJECT or -++ * ARRAY sort for <tt>.class</tt> constants, for classes whose -++ * version is 49.0, a {@link Type} of METHOD sort or a -++ * {@link Handle} for MethodType and MethodHandle constants, for -++ * classes whose version is 51.0. -++ */ -++ public void visitLdcInsn(Object cst) { -++ if (mv != null) { -++ mv.visitLdcInsn(cst); -++ } -++ } -++ -++ /** -++ * Visits an IINC instruction. -++ * -++ * @param var -++ * index of the local variable to be incremented. -++ * @param increment -++ * amount to increment the local variable by. -++ */ -++ public void visitIincInsn(int var, int increment) { -++ if (mv != null) { -++ mv.visitIincInsn(var, increment); -++ } -++ } -++ -++ /** -++ * Visits a TABLESWITCH instruction. -++ * -++ * @param min -++ * the minimum key value. -++ * @param max -++ * the maximum key value. -++ * @param dflt -++ * beginning of the default handler block. -++ * @param labels -++ * beginnings of the handler blocks. <tt>labels[i]</tt> is the -++ * beginning of the handler block for the <tt>min + i</tt> key. -++ */ -++ public void visitTableSwitchInsn(int min, int max, Label dflt, -++ Label... labels) { -++ if (mv != null) { -++ mv.visitTableSwitchInsn(min, max, dflt, labels); -++ } -++ } -++ -++ /** -++ * Visits a LOOKUPSWITCH instruction. -++ * -++ * @param dflt -++ * beginning of the default handler block. -++ * @param keys -++ * the values of the keys. -++ * @param labels -++ * beginnings of the handler blocks. <tt>labels[i]</tt> is the -++ * beginning of the handler block for the <tt>keys[i]</tt> key. -++ */ -++ public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { -++ if (mv != null) { -++ mv.visitLookupSwitchInsn(dflt, keys, labels); -++ } -++ } -++ -++ /** -++ * Visits a MULTIANEWARRAY instruction. -++ * -++ * @param desc -++ * an array type descriptor (see {@link Type Type}). -++ * @param dims -++ * number of dimensions of the array to allocate. -++ */ -++ public void visitMultiANewArrayInsn(String desc, int dims) { -++ if (mv != null) { -++ mv.visitMultiANewArrayInsn(desc, dims); -++ } -++ } -++ -++ /** -++ * Visits an annotation on an instruction. This method must be called just -++ * <i>after</i> the annotated instruction. It can be called several times -++ * for the same instruction. -++ * -++ * @param typeRef -++ * a reference to the annotated type. The sort of this type -++ * reference must be {@link TypeReference#INSTANCEOF INSTANCEOF}, -++ * {@link TypeReference#NEW NEW}, -++ * {@link TypeReference#CONSTRUCTOR_REFERENCE -++ * CONSTRUCTOR_REFERENCE}, {@link TypeReference#METHOD_REFERENCE -++ * METHOD_REFERENCE}, {@link TypeReference#CAST CAST}, -++ * {@link TypeReference#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT -++ * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, -++ * {@link TypeReference#METHOD_INVOCATION_TYPE_ARGUMENT -++ * METHOD_INVOCATION_TYPE_ARGUMENT}, -++ * {@link TypeReference#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT -++ * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or -++ * {@link TypeReference#METHOD_REFERENCE_TYPE_ARGUMENT -++ * METHOD_REFERENCE_TYPE_ARGUMENT}. See {@link TypeReference}. -++ * @param typePath -++ * the path to the annotated type argument, wildcard bound, array -++ * element type, or static inner type within 'typeRef'. May be -++ * <tt>null</tt> if the annotation targets 'typeRef' as a whole. -++ * @param desc -++ * the class descriptor of the annotation class. -++ * @param visible -++ * <tt>true</tt> if the annotation is visible at runtime. -++ * @return a visitor to visit the annotation values, or <tt>null</tt> if -++ * this visitor is not interested in visiting this annotation. -++ */ -++ public AnnotationVisitor visitInsnAnnotation(int typeRef, -++ TypePath typePath, String desc, boolean visible) { -++ if (api < Opcodes.ASM5) { -++ throw new RuntimeException(); -++ } -++ if (mv != null) { -++ return mv.visitInsnAnnotation(typeRef, typePath, desc, visible); -++ } -++ return null; -++ } -++ -++ // ------------------------------------------------------------------------- -++ // Exceptions table entries, debug information, max stack and max locals -++ // ------------------------------------------------------------------------- -++ -++ /** -++ * Visits a try catch block. -++ * -++ * @param start -++ * beginning of the exception handler's scope (inclusive). -++ * @param end -++ * end of the exception handler's scope (exclusive). -++ * @param handler -++ * beginning of the exception handler's code. -++ * @param type -++ * internal name of the type of exceptions handled by the -++ * handler, or <tt>null</tt> to catch any exceptions (for -++ * "finally" blocks). -++ * @throws IllegalArgumentException -++ * if one of the labels has already been visited by this visitor -++ * (by the {@link #visitLabel visitLabel} method). -++ */ -++ public void visitTryCatchBlock(Label start, Label end, Label handler, -++ String type) { -++ if (mv != null) { -++ mv.visitTryCatchBlock(start, end, handler, type); -++ } -++ } -++ -++ /** -++ * Visits an annotation on an exception handler type. This method must be -++ * called <i>after</i> the {@link #visitTryCatchBlock} for the annotated -++ * exception handler. It can be called several times for the same exception -++ * handler. -++ * -++ * @param typeRef -++ * a reference to the annotated type. The sort of this type -++ * reference must be {@link TypeReference#EXCEPTION_PARAMETER -++ * EXCEPTION_PARAMETER}. See {@link TypeReference}. -++ * @param typePath -++ * the path to the annotated type argument, wildcard bound, array -++ * element type, or static inner type within 'typeRef'. May be -++ * <tt>null</tt> if the annotation targets 'typeRef' as a whole. -++ * @param desc -++ * the class descriptor of the annotation class. -++ * @param visible -++ * <tt>true</tt> if the annotation is visible at runtime. -++ * @return a visitor to visit the annotation values, or <tt>null</tt> if -++ * this visitor is not interested in visiting this annotation. -++ */ -++ public AnnotationVisitor visitTryCatchAnnotation(int typeRef, -++ TypePath typePath, String desc, boolean visible) { -++ if (api < Opcodes.ASM5) { -++ throw new RuntimeException(); -++ } -++ if (mv != null) { -++ return mv.visitTryCatchAnnotation(typeRef, typePath, desc, visible); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits a local variable declaration. -++ * -++ * @param name -++ * the name of a local variable. -++ * @param desc -++ * the type descriptor of this local variable. -++ * @param signature -++ * the type signature of this local variable. May be -++ * <tt>null</tt> if the local variable type does not use generic -++ * types. -++ * @param start -++ * the first instruction corresponding to the scope of this local -++ * variable (inclusive). -++ * @param end -++ * the last instruction corresponding to the scope of this local -++ * variable (exclusive). -++ * @param index -++ * the local variable's index. -++ * @throws IllegalArgumentException -++ * if one of the labels has not already been visited by this -++ * visitor (by the {@link #visitLabel visitLabel} method). -++ */ -++ public void visitLocalVariable(String name, String desc, String signature, -++ Label start, Label end, int index) { -++ if (mv != null) { -++ mv.visitLocalVariable(name, desc, signature, start, end, index); -++ } -++ } -++ -++ /** -++ * Visits an annotation on a local variable type. -++ * -++ * @param typeRef -++ * a reference to the annotated type. The sort of this type -++ * reference must be {@link TypeReference#LOCAL_VARIABLE -++ * LOCAL_VARIABLE} or {@link TypeReference#RESOURCE_VARIABLE -++ * RESOURCE_VARIABLE}. See {@link TypeReference}. -++ * @param typePath -++ * the path to the annotated type argument, wildcard bound, array -++ * element type, or static inner type within 'typeRef'. May be -++ * <tt>null</tt> if the annotation targets 'typeRef' as a whole. -++ * @param start -++ * the fist instructions corresponding to the continuous ranges -++ * that make the scope of this local variable (inclusive). -++ * @param end -++ * the last instructions corresponding to the continuous ranges -++ * that make the scope of this local variable (exclusive). This -++ * array must have the same size as the 'start' array. -++ * @param index -++ * the local variable's index in each range. This array must have -++ * the same size as the 'start' array. -++ * @param desc -++ * the class descriptor of the annotation class. -++ * @param visible -++ * <tt>true</tt> if the annotation is visible at runtime. -++ * @return a visitor to visit the annotation values, or <tt>null</tt> if -++ * this visitor is not interested in visiting this annotation. -++ */ -++ public AnnotationVisitor visitLocalVariableAnnotation(int typeRef, -++ TypePath typePath, Label[] start, Label[] end, int[] index, -++ String desc, boolean visible) { -++ if (api < Opcodes.ASM5) { -++ throw new RuntimeException(); -++ } -++ if (mv != null) { -++ return mv.visitLocalVariableAnnotation(typeRef, typePath, start, -++ end, index, desc, visible); -++ } -++ return null; -++ } -++ -++ /** -++ * Visits a line number declaration. -++ * -++ * @param line -++ * a line number. This number refers to the source file from -++ * which the class was compiled. -++ * @param start -++ * the first instruction corresponding to this line number. -++ * @throws IllegalArgumentException -++ * if <tt>start</tt> has not already been visited by this -++ * visitor (by the {@link #visitLabel visitLabel} method). -++ */ -++ public void visitLineNumber(int line, Label start) { -++ if (mv != null) { -++ mv.visitLineNumber(line, start); -++ } -++ } -++ -++ /** -++ * Visits the maximum stack size and the maximum number of local variables -++ * of the method. -++ * -++ * @param maxStack -++ * maximum stack size of the method. -++ * @param maxLocals -++ * maximum number of local variables for the method. -++ */ -++ public void visitMaxs(int maxStack, int maxLocals) { -++ if (mv != null) { -++ mv.visitMaxs(maxStack, maxLocals); -++ } -++ } -++ -++ /** -++ * Visits the end of the method. This method, which is the last one to be -++ * called, is used to inform the visitor that all the annotations and -++ * attributes of the method have been visited. -++ */ -++ public void visitEnd() { -++ if (mv != null) { -++ mv.visitEnd(); -++ } -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/MethodWriter.java b/contrib/asm/src/org/objectweb/asm/MethodWriter.java -+new file mode 100644 -+index 0000000..ceca3f8 -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/MethodWriter.java -+@@ -0,0 +1,2915 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * A {@link MethodVisitor} that generates methods in bytecode form. Each visit -++ * method of this class appends the bytecode corresponding to the visited -++ * instruction to a byte vector, in the order these methods are called. -++ * -++ * @author Eric Bruneton -++ * @author Eugene Kuleshov -++ */ -++class MethodWriter extends MethodVisitor { -++ -++ /** -++ * Pseudo access flag used to denote constructors. -++ */ -++ static final int ACC_CONSTRUCTOR = 0x80000; -++ -++ /** -++ * Frame has exactly the same locals as the previous stack map frame and -++ * number of stack items is zero. -++ */ -++ static final int SAME_FRAME = 0; // to 63 (0-3f) -++ -++ /** -++ * Frame has exactly the same locals as the previous stack map frame and -++ * number of stack items is 1 -++ */ -++ static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; // to 127 (40-7f) -++ -++ /** -++ * Reserved for future use -++ */ -++ static final int RESERVED = 128; -++ -++ /** -++ * Frame has exactly the same locals as the previous stack map frame and -++ * number of stack items is 1. Offset is bigger then 63; -++ */ -++ static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; // f7 -++ -++ /** -++ * Frame where current locals are the same as the locals in the previous -++ * frame, except that the k last locals are absent. The value of k is given -++ * by the formula 251-frame_type. -++ */ -++ static final int CHOP_FRAME = 248; // to 250 (f8-fA) -++ -++ /** -++ * Frame has exactly the same locals as the previous stack map frame and -++ * number of stack items is zero. Offset is bigger then 63; -++ */ -++ static final int SAME_FRAME_EXTENDED = 251; // fb -++ -++ /** -++ * Frame where current locals are the same as the locals in the previous -++ * frame, except that k additional locals are defined. The value of k is -++ * given by the formula frame_type-251. -++ */ -++ static final int APPEND_FRAME = 252; // to 254 // fc-fe -++ -++ /** -++ * Full frame -++ */ -++ static final int FULL_FRAME = 255; // ff -++ -++ /** -++ * Indicates that the stack map frames must be recomputed from scratch. In -++ * this case the maximum stack size and number of local variables is also -++ * recomputed from scratch. -++ * -++ * @see #compute -++ */ -++ private static final int FRAMES = 0; -++ -++ /** -++ * Indicates that the maximum stack size and number of local variables must -++ * be automatically computed. -++ * -++ * @see #compute -++ */ -++ private static final int MAXS = 1; -++ -++ /** -++ * Indicates that nothing must be automatically computed. -++ * -++ * @see #compute -++ */ -++ private static final int NOTHING = 2; -++ -++ /** -++ * The class writer to which this method must be added. -++ */ -++ final ClassWriter cw; -++ -++ /** -++ * Access flags of this method. -++ */ -++ private int access; -++ -++ /** -++ * The index of the constant pool item that contains the name of this -++ * method. -++ */ -++ private final int name; -++ -++ /** -++ * The index of the constant pool item that contains the descriptor of this -++ * method. -++ */ -++ private final int desc; -++ -++ /** -++ * The descriptor of this method. -++ */ -++ private final String descriptor; -++ -++ /** -++ * The signature of this method. -++ */ -++ String signature; -++ -++ /** -++ * If not zero, indicates that the code of this method must be copied from -++ * the ClassReader associated to this writer in <code>cw.cr</code>. More -++ * precisely, this field gives the index of the first byte to copied from -++ * <code>cw.cr.b</code>. -++ */ -++ int classReaderOffset; -++ -++ /** -++ * If not zero, indicates that the code of this method must be copied from -++ * the ClassReader associated to this writer in <code>cw.cr</code>. More -++ * precisely, this field gives the number of bytes to copied from -++ * <code>cw.cr.b</code>. -++ */ -++ int classReaderLength; -++ -++ /** -++ * Number of exceptions that can be thrown by this method. -++ */ -++ int exceptionCount; -++ -++ /** -++ * The exceptions that can be thrown by this method. More precisely, this -++ * array contains the indexes of the constant pool items that contain the -++ * internal names of these exception classes. -++ */ -++ int[] exceptions; -++ -++ /** -++ * The annotation default attribute of this method. May be <tt>null</tt>. -++ */ -++ private ByteVector annd; -++ -++ /** -++ * The runtime visible annotations of this method. May be <tt>null</tt>. -++ */ -++ private AnnotationWriter anns; -++ -++ /** -++ * The runtime invisible annotations of this method. May be <tt>null</tt>. -++ */ -++ private AnnotationWriter ianns; -++ -++ /** -++ * The runtime visible type annotations of this method. May be <tt>null</tt> -++ * . -++ */ -++ private AnnotationWriter tanns; -++ -++ /** -++ * The runtime invisible type annotations of this method. May be -++ * <tt>null</tt>. -++ */ -++ private AnnotationWriter itanns; -++ -++ /** -++ * The runtime visible parameter annotations of this method. May be -++ * <tt>null</tt>. -++ */ -++ private AnnotationWriter[] panns; -++ -++ /** -++ * The runtime invisible parameter annotations of this method. May be -++ * <tt>null</tt>. -++ */ -++ private AnnotationWriter[] ipanns; -++ -++ /** -++ * The number of synthetic parameters of this method. -++ */ -++ private int synthetics; -++ -++ /** -++ * The non standard attributes of the method. -++ */ -++ private Attribute attrs; -++ -++ /** -++ * The bytecode of this method. -++ */ -++ private ByteVector code = new ByteVector(); -++ -++ /** -++ * Maximum stack size of this method. -++ */ -++ private int maxStack; -++ -++ /** -++ * Maximum number of local variables for this method. -++ */ -++ private int maxLocals; -++ -++ /** -++ * Number of local variables in the current stack map frame. -++ */ -++ private int currentLocals; -++ -++ /** -++ * Number of stack map frames in the StackMapTable attribute. -++ */ -++ private int frameCount; -++ -++ /** -++ * The StackMapTable attribute. -++ */ -++ private ByteVector stackMap; -++ -++ /** -++ * The offset of the last frame that was written in the StackMapTable -++ * attribute. -++ */ -++ private int previousFrameOffset; -++ -++ /** -++ * The last frame that was written in the StackMapTable attribute. -++ * -++ * @see #frame -++ */ -++ private int[] previousFrame; -++ -++ /** -++ * The current stack map frame. The first element contains the offset of the -++ * instruction to which the frame corresponds, the second element is the -++ * number of locals and the third one is the number of stack elements. The -++ * local variables start at index 3 and are followed by the operand stack -++ * values. In summary frame[0] = offset, frame[1] = nLocal, frame[2] = -++ * nStack, frame[3] = nLocal. All types are encoded as integers, with the -++ * same format as the one used in {@link Label}, but limited to BASE types. -++ */ -++ private int[] frame; -++ -++ /** -++ * Number of elements in the exception handler list. -++ */ -++ private int handlerCount; -++ -++ /** -++ * The first element in the exception handler list. -++ */ -++ private Handler firstHandler; -++ -++ /** -++ * The last element in the exception handler list. -++ */ -++ private Handler lastHandler; -++ -++ /** -++ * Number of entries in the MethodParameters attribute. -++ */ -++ private int methodParametersCount; -++ -++ /** -++ * The MethodParameters attribute. -++ */ -++ private ByteVector methodParameters; -++ -++ /** -++ * Number of entries in the LocalVariableTable attribute. -++ */ -++ private int localVarCount; -++ -++ /** -++ * The LocalVariableTable attribute. -++ */ -++ private ByteVector localVar; -++ -++ /** -++ * Number of entries in the LocalVariableTypeTable attribute. -++ */ -++ private int localVarTypeCount; -++ -++ /** -++ * The LocalVariableTypeTable attribute. -++ */ -++ private ByteVector localVarType; -++ -++ /** -++ * Number of entries in the LineNumberTable attribute. -++ */ -++ private int lineNumberCount; -++ -++ /** -++ * The LineNumberTable attribute. -++ */ -++ private ByteVector lineNumber; -++ -++ /** -++ * The start offset of the last visited instruction. -++ */ -++ private int lastCodeOffset; -++ -++ /** -++ * The runtime visible type annotations of the code. May be <tt>null</tt>. -++ */ -++ private AnnotationWriter ctanns; -++ -++ /** -++ * The runtime invisible type annotations of the code. May be <tt>null</tt>. -++ */ -++ private AnnotationWriter ictanns; -++ -++ /** -++ * The non standard attributes of the method's code. -++ */ -++ private Attribute cattrs; -++ -++ /** -++ * Indicates if some jump instructions are too small and need to be resized. -++ */ -++ private boolean resize; -++ -++ /** -++ * The number of subroutines in this method. -++ */ -++ private int subroutines; -++ -++ // ------------------------------------------------------------------------ -++ -++ /* -++ * Fields for the control flow graph analysis algorithm (used to compute the -++ * maximum stack size). A control flow graph contains one node per "basic -++ * block", and one edge per "jump" from one basic block to another. Each -++ * node (i.e., each basic block) is represented by the Label object that -++ * corresponds to the first instruction of this basic block. Each node also -++ * stores the list of its successors in the graph, as a linked list of Edge -++ * objects. -++ */ -++ -++ /** -++ * Indicates what must be automatically computed. -++ * -++ * @see #FRAMES -++ * @see #MAXS -++ * @see #NOTHING -++ */ -++ private final int compute; -++ -++ /** -++ * A list of labels. This list is the list of basic blocks in the method, -++ * i.e. a list of Label objects linked to each other by their -++ * {@link Label#successor} field, in the order they are visited by -++ * {@link MethodVisitor#visitLabel}, and starting with the first basic -++ * block. -++ */ -++ private Label labels; -++ -++ /** -++ * The previous basic block. -++ */ -++ private Label previousBlock; -++ -++ /** -++ * The current basic block. -++ */ -++ private Label currentBlock; -++ -++ /** -++ * The (relative) stack size after the last visited instruction. This size -++ * is relative to the beginning of the current basic block, i.e., the true -++ * stack size after the last visited instruction is equal to the -++ * {@link Label#inputStackTop beginStackSize} of the current basic block -++ * plus <tt>stackSize</tt>. -++ */ -++ private int stackSize; -++ -++ /** -++ * The (relative) maximum stack size after the last visited instruction. -++ * This size is relative to the beginning of the current basic block, i.e., -++ * the true maximum stack size after the last visited instruction is equal -++ * to the {@link Label#inputStackTop beginStackSize} of the current basic -++ * block plus <tt>stackSize</tt>. -++ */ -++ private int maxStackSize; -++ -++ // ------------------------------------------------------------------------ -++ // Constructor -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Constructs a new {@link MethodWriter}. -++ * -++ * @param cw -++ * the class writer in which the method must be added. -++ * @param access -++ * the method's access flags (see {@link Opcodes}). -++ * @param name -++ * the method's name. -++ * @param desc -++ * the method's descriptor (see {@link Type}). -++ * @param signature -++ * the method's signature. May be <tt>null</tt>. -++ * @param exceptions -++ * the internal names of the method's exceptions. May be -++ * <tt>null</tt>. -++ * @param computeMaxs -++ * <tt>true</tt> if the maximum stack size and number of local -++ * variables must be automatically computed. -++ * @param computeFrames -++ * <tt>true</tt> if the stack map tables must be recomputed from -++ * scratch. -++ */ -++ MethodWriter(final ClassWriter cw, final int access, final String name, -++ final String desc, final String signature, -++ final String[] exceptions, final boolean computeMaxs, -++ final boolean computeFrames) { -++ super(Opcodes.ASM5); -++ if (cw.firstMethod == null) { -++ cw.firstMethod = this; -++ } else { -++ cw.lastMethod.mv = this; -++ } -++ cw.lastMethod = this; -++ this.cw = cw; -++ this.access = access; -++ if ("<init>".equals(name)) { -++ this.access |= ACC_CONSTRUCTOR; -++ } -++ this.name = cw.newUTF8(name); -++ this.desc = cw.newUTF8(desc); -++ this.descriptor = desc; -++ if (ClassReader.SIGNATURES) { -++ this.signature = signature; -++ } -++ if (exceptions != null && exceptions.length > 0) { -++ exceptionCount = exceptions.length; -++ this.exceptions = new int[exceptionCount]; -++ for (int i = 0; i < exceptionCount; ++i) { -++ this.exceptions[i] = cw.newClass(exceptions[i]); -++ } -++ } -++ this.compute = computeFrames ? FRAMES : (computeMaxs ? MAXS : NOTHING); -++ if (computeMaxs || computeFrames) { -++ // updates maxLocals -++ int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2; -++ if ((access & Opcodes.ACC_STATIC) != 0) { -++ --size; -++ } -++ maxLocals = size; -++ currentLocals = size; -++ // creates and visits the label for the first basic block -++ labels = new Label(); -++ labels.status |= Label.PUSHED; -++ visitLabel(labels); -++ } -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Implementation of the MethodVisitor abstract class -++ // ------------------------------------------------------------------------ -++ -++ @Override -++ public void visitParameter(String name, int access) { -++ if (methodParameters == null) { -++ methodParameters = new ByteVector(); -++ } -++ ++methodParametersCount; -++ methodParameters.putShort((name == null) ? 0 : cw.newUTF8(name)) -++ .putShort(access); -++ } -++ -++ @Override -++ public AnnotationVisitor visitAnnotationDefault() { -++ if (!ClassReader.ANNOTATIONS) { -++ return null; -++ } -++ annd = new ByteVector(); -++ return new AnnotationWriter(cw, false, annd, null, 0); -++ } -++ -++ @Override -++ public AnnotationVisitor visitAnnotation(final String desc, -++ final boolean visible) { -++ if (!ClassReader.ANNOTATIONS) { -++ return null; -++ } -++ ByteVector bv = new ByteVector(); -++ // write type, and reserve space for values count -++ bv.putShort(cw.newUTF8(desc)).putShort(0); -++ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); -++ if (visible) { -++ aw.next = anns; -++ anns = aw; -++ } else { -++ aw.next = ianns; -++ ianns = aw; -++ } -++ return aw; -++ } -++ -++ @Override -++ public AnnotationVisitor visitTypeAnnotation(final int typeRef, -++ final TypePath typePath, final String desc, final boolean visible) { -++ if (!ClassReader.ANNOTATIONS) { -++ return null; -++ } -++ ByteVector bv = new ByteVector(); -++ // write target_type and target_info -++ AnnotationWriter.putTarget(typeRef, typePath, bv); -++ // write type, and reserve space for values count -++ bv.putShort(cw.newUTF8(desc)).putShort(0); -++ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, -++ bv.length - 2); -++ if (visible) { -++ aw.next = tanns; -++ tanns = aw; -++ } else { -++ aw.next = itanns; -++ itanns = aw; -++ } -++ return aw; -++ } -++ -++ @Override -++ public AnnotationVisitor visitParameterAnnotation(final int parameter, -++ final String desc, final boolean visible) { -++ if (!ClassReader.ANNOTATIONS) { -++ return null; -++ } -++ ByteVector bv = new ByteVector(); -++ if ("Ljava/lang/Synthetic;".equals(desc)) { -++ // workaround for a bug in javac with synthetic parameters -++ // see ClassReader.readParameterAnnotations -++ synthetics = Math.max(synthetics, parameter + 1); -++ return new AnnotationWriter(cw, false, bv, null, 0); -++ } -++ // write type, and reserve space for values count -++ bv.putShort(cw.newUTF8(desc)).putShort(0); -++ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); -++ if (visible) { -++ if (panns == null) { -++ panns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; -++ } -++ aw.next = panns[parameter]; -++ panns[parameter] = aw; -++ } else { -++ if (ipanns == null) { -++ ipanns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; -++ } -++ aw.next = ipanns[parameter]; -++ ipanns[parameter] = aw; -++ } -++ return aw; -++ } -++ -++ @Override -++ public void visitAttribute(final Attribute attr) { -++ if (attr.isCodeAttribute()) { -++ attr.next = cattrs; -++ cattrs = attr; -++ } else { -++ attr.next = attrs; -++ attrs = attr; -++ } -++ } -++ -++ @Override -++ public void visitCode() { -++ } -++ -++ @Override -++ public void visitFrame(final int type, final int nLocal, -++ final Object[] local, final int nStack, final Object[] stack) { -++ if (!ClassReader.FRAMES || compute == FRAMES) { -++ return; -++ } -++ -++ if (type == Opcodes.F_NEW) { -++ if (previousFrame == null) { -++ visitImplicitFirstFrame(); -++ } -++ currentLocals = nLocal; -++ int frameIndex = startFrame(code.length, nLocal, nStack); -++ for (int i = 0; i < nLocal; ++i) { -++ if (local[i] instanceof String) { -++ frame[frameIndex++] = Frame.OBJECT -++ | cw.addType((String) local[i]); -++ } else if (local[i] instanceof Integer) { -++ frame[frameIndex++] = ((Integer) local[i]).intValue(); -++ } else { -++ frame[frameIndex++] = Frame.UNINITIALIZED -++ | cw.addUninitializedType("", -++ ((Label) local[i]).position); -++ } -++ } -++ for (int i = 0; i < nStack; ++i) { -++ if (stack[i] instanceof String) { -++ frame[frameIndex++] = Frame.OBJECT -++ | cw.addType((String) stack[i]); -++ } else if (stack[i] instanceof Integer) { -++ frame[frameIndex++] = ((Integer) stack[i]).intValue(); -++ } else { -++ frame[frameIndex++] = Frame.UNINITIALIZED -++ | cw.addUninitializedType("", -++ ((Label) stack[i]).position); -++ } -++ } -++ endFrame(); -++ } else { -++ int delta; -++ if (stackMap == null) { -++ stackMap = new ByteVector(); -++ delta = code.length; -++ } else { -++ delta = code.length - previousFrameOffset - 1; -++ if (delta < 0) { -++ if (type == Opcodes.F_SAME) { -++ return; -++ } else { -++ throw new IllegalStateException(); -++ } -++ } -++ } -++ -++ switch (type) { -++ case Opcodes.F_FULL: -++ currentLocals = nLocal; -++ stackMap.putByte(FULL_FRAME).putShort(delta).putShort(nLocal); -++ for (int i = 0; i < nLocal; ++i) { -++ writeFrameType(local[i]); -++ } -++ stackMap.putShort(nStack); -++ for (int i = 0; i < nStack; ++i) { -++ writeFrameType(stack[i]); -++ } -++ break; -++ case Opcodes.F_APPEND: -++ currentLocals += nLocal; -++ stackMap.putByte(SAME_FRAME_EXTENDED + nLocal).putShort(delta); -++ for (int i = 0; i < nLocal; ++i) { -++ writeFrameType(local[i]); -++ } -++ break; -++ case Opcodes.F_CHOP: -++ currentLocals -= nLocal; -++ stackMap.putByte(SAME_FRAME_EXTENDED - nLocal).putShort(delta); -++ break; -++ case Opcodes.F_SAME: -++ if (delta < 64) { -++ stackMap.putByte(delta); -++ } else { -++ stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta); -++ } -++ break; -++ case Opcodes.F_SAME1: -++ if (delta < 64) { -++ stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); -++ } else { -++ stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) -++ .putShort(delta); -++ } -++ writeFrameType(stack[0]); -++ break; -++ } -++ -++ previousFrameOffset = code.length; -++ ++frameCount; -++ } -++ -++ maxStack = Math.max(maxStack, nStack); -++ maxLocals = Math.max(maxLocals, currentLocals); -++ } -++ -++ @Override -++ public void visitInsn(final int opcode) { -++ lastCodeOffset = code.length; -++ // adds the instruction to the bytecode of the method -++ code.putByte(opcode); -++ // update currentBlock -++ // Label currentBlock = this.currentBlock; -++ if (currentBlock != null) { -++ if (compute == FRAMES) { -++ currentBlock.frame.execute(opcode, 0, null, null); -++ } else { -++ // updates current and max stack sizes -++ int size = stackSize + Frame.SIZE[opcode]; -++ if (size > maxStackSize) { -++ maxStackSize = size; -++ } -++ stackSize = size; -++ } -++ // if opcode == ATHROW or xRETURN, ends current block (no successor) -++ if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) -++ || opcode == Opcodes.ATHROW) { -++ noSuccessor(); -++ } -++ } -++ } -++ -++ @Override -++ public void visitIntInsn(final int opcode, final int operand) { -++ lastCodeOffset = code.length; -++ // Label currentBlock = this.currentBlock; -++ if (currentBlock != null) { -++ if (compute == FRAMES) { -++ currentBlock.frame.execute(opcode, operand, null, null); -++ } else if (opcode != Opcodes.NEWARRAY) { -++ // updates current and max stack sizes only for NEWARRAY -++ // (stack size variation = 0 for BIPUSH or SIPUSH) -++ int size = stackSize + 1; -++ if (size > maxStackSize) { -++ maxStackSize = size; -++ } -++ stackSize = size; -++ } -++ } -++ // adds the instruction to the bytecode of the method -++ if (opcode == Opcodes.SIPUSH) { -++ code.put12(opcode, operand); -++ } else { // BIPUSH or NEWARRAY -++ code.put11(opcode, operand); -++ } -++ } -++ -++ @Override -++ public void visitVarInsn(final int opcode, final int var) { -++ lastCodeOffset = code.length; -++ // Label currentBlock = this.currentBlock; -++ if (currentBlock != null) { -++ if (compute == FRAMES) { -++ currentBlock.frame.execute(opcode, var, null, null); -++ } else { -++ // updates current and max stack sizes -++ if (opcode == Opcodes.RET) { -++ // no stack change, but end of current block (no successor) -++ currentBlock.status |= Label.RET; -++ // save 'stackSize' here for future use -++ // (see {@link #findSubroutineSuccessors}) -++ currentBlock.inputStackTop = stackSize; -++ noSuccessor(); -++ } else { // xLOAD or xSTORE -++ int size = stackSize + Frame.SIZE[opcode]; -++ if (size > maxStackSize) { -++ maxStackSize = size; -++ } -++ stackSize = size; -++ } -++ } -++ } -++ if (compute != NOTHING) { -++ // updates max locals -++ int n; -++ if (opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD -++ || opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE) { -++ n = var + 2; -++ } else { -++ n = var + 1; -++ } -++ if (n > maxLocals) { -++ maxLocals = n; -++ } -++ } -++ // adds the instruction to the bytecode of the method -++ if (var < 4 && opcode != Opcodes.RET) { -++ int opt; -++ if (opcode < Opcodes.ISTORE) { -++ /* ILOAD_0 */ -++ opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var; -++ } else { -++ /* ISTORE_0 */ -++ opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var; -++ } -++ code.putByte(opt); -++ } else if (var >= 256) { -++ code.putByte(196 /* WIDE */).put12(opcode, var); -++ } else { -++ code.put11(opcode, var); -++ } -++ if (opcode >= Opcodes.ISTORE && compute == FRAMES && handlerCount > 0) { -++ visitLabel(new Label()); -++ } -++ } -++ -++ @Override -++ public void visitTypeInsn(final int opcode, final String type) { -++ lastCodeOffset = code.length; -++ Item i = cw.newClassItem(type); -++ // Label currentBlock = this.currentBlock; -++ if (currentBlock != null) { -++ if (compute == FRAMES) { -++ currentBlock.frame.execute(opcode, code.length, cw, i); -++ } else if (opcode == Opcodes.NEW) { -++ // updates current and max stack sizes only if opcode == NEW -++ // (no stack change for ANEWARRAY, CHECKCAST, INSTANCEOF) -++ int size = stackSize + 1; -++ if (size > maxStackSize) { -++ maxStackSize = size; -++ } -++ stackSize = size; -++ } -++ } -++ // adds the instruction to the bytecode of the method -++ code.put12(opcode, i.index); -++ } -++ -++ @Override -++ public void visitFieldInsn(final int opcode, final String owner, -++ final String name, final String desc) { -++ lastCodeOffset = code.length; -++ Item i = cw.newFieldItem(owner, name, desc); -++ // Label currentBlock = this.currentBlock; -++ if (currentBlock != null) { -++ if (compute == FRAMES) { -++ currentBlock.frame.execute(opcode, 0, cw, i); -++ } else { -++ int size; -++ // computes the stack size variation -++ char c = desc.charAt(0); -++ switch (opcode) { -++ case Opcodes.GETSTATIC: -++ size = stackSize + (c == 'D' || c == 'J' ? 2 : 1); -++ break; -++ case Opcodes.PUTSTATIC: -++ size = stackSize + (c == 'D' || c == 'J' ? -2 : -1); -++ break; -++ case Opcodes.GETFIELD: -++ size = stackSize + (c == 'D' || c == 'J' ? 1 : 0); -++ break; -++ // case Constants.PUTFIELD: -++ default: -++ size = stackSize + (c == 'D' || c == 'J' ? -3 : -2); -++ break; -++ } -++ // updates current and max stack sizes -++ if (size > maxStackSize) { -++ maxStackSize = size; -++ } -++ stackSize = size; -++ } -++ } -++ // adds the instruction to the bytecode of the method -++ code.put12(opcode, i.index); -++ } -++ -++ @Override -++ public void visitMethodInsn(final int opcode, final String owner, -++ final String name, final String desc, final boolean itf) { -++ lastCodeOffset = code.length; -++ Item i = cw.newMethodItem(owner, name, desc, itf); -++ int argSize = i.intVal; -++ // Label currentBlock = this.currentBlock; -++ if (currentBlock != null) { -++ if (compute == FRAMES) { -++ currentBlock.frame.execute(opcode, 0, cw, i); -++ } else { -++ /* -++ * computes the stack size variation. In order not to recompute -++ * several times this variation for the same Item, we use the -++ * intVal field of this item to store this variation, once it -++ * has been computed. More precisely this intVal field stores -++ * the sizes of the arguments and of the return value -++ * corresponding to desc. -++ */ -++ if (argSize == 0) { -++ // the above sizes have not been computed yet, -++ // so we compute them... -++ argSize = Type.getArgumentsAndReturnSizes(desc); -++ // ... and we save them in order -++ // not to recompute them in the future -++ i.intVal = argSize; -++ } -++ int size; -++ if (opcode == Opcodes.INVOKESTATIC) { -++ size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1; -++ } else { -++ size = stackSize - (argSize >> 2) + (argSize & 0x03); -++ } -++ // updates current and max stack sizes -++ if (size > maxStackSize) { -++ maxStackSize = size; -++ } -++ stackSize = size; -++ } -++ } -++ // adds the instruction to the bytecode of the method -++ if (opcode == Opcodes.INVOKEINTERFACE) { -++ if (argSize == 0) { -++ argSize = Type.getArgumentsAndReturnSizes(desc); -++ i.intVal = argSize; -++ } -++ code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0); -++ } else { -++ code.put12(opcode, i.index); -++ } -++ } -++ -++ @Override -++ public void visitInvokeDynamicInsn(final String name, final String desc, -++ final Handle bsm, final Object... bsmArgs) { -++ lastCodeOffset = code.length; -++ Item i = cw.newInvokeDynamicItem(name, desc, bsm, bsmArgs); -++ int argSize = i.intVal; -++ // Label currentBlock = this.currentBlock; -++ if (currentBlock != null) { -++ if (compute == FRAMES) { -++ currentBlock.frame.execute(Opcodes.INVOKEDYNAMIC, 0, cw, i); -++ } else { -++ /* -++ * computes the stack size variation. In order not to recompute -++ * several times this variation for the same Item, we use the -++ * intVal field of this item to store this variation, once it -++ * has been computed. More precisely this intVal field stores -++ * the sizes of the arguments and of the return value -++ * corresponding to desc. -++ */ -++ if (argSize == 0) { -++ // the above sizes have not been computed yet, -++ // so we compute them... -++ argSize = Type.getArgumentsAndReturnSizes(desc); -++ // ... and we save them in order -++ // not to recompute them in the future -++ i.intVal = argSize; -++ } -++ int size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1; -++ -++ // updates current and max stack sizes -++ if (size > maxStackSize) { -++ maxStackSize = size; -++ } -++ stackSize = size; -++ } -++ } -++ // adds the instruction to the bytecode of the method -++ code.put12(Opcodes.INVOKEDYNAMIC, i.index); -++ code.putShort(0); -++ } -++ -++ @Override -++ public void visitJumpInsn(final int opcode, final Label label) { -++ lastCodeOffset = code.length; -++ Label nextInsn = null; -++ // Label currentBlock = this.currentBlock; -++ if (currentBlock != null) { -++ if (compute == FRAMES) { -++ currentBlock.frame.execute(opcode, 0, null, null); -++ // 'label' is the target of a jump instruction -++ label.getFirst().status |= Label.TARGET; -++ // adds 'label' as a successor of this basic block -++ addSuccessor(Edge.NORMAL, label); -++ if (opcode != Opcodes.GOTO) { -++ // creates a Label for the next basic block -++ nextInsn = new Label(); -++ } -++ } else { -++ if (opcode == Opcodes.JSR) { -++ if ((label.status & Label.SUBROUTINE) == 0) { -++ label.status |= Label.SUBROUTINE; -++ ++subroutines; -++ } -++ currentBlock.status |= Label.JSR; -++ addSuccessor(stackSize + 1, label); -++ // creates a Label for the next basic block -++ nextInsn = new Label(); -++ /* -++ * note that, by construction in this method, a JSR block -++ * has at least two successors in the control flow graph: -++ * the first one leads the next instruction after the JSR, -++ * while the second one leads to the JSR target. -++ */ -++ } else { -++ // updates current stack size (max stack size unchanged -++ // because stack size variation always negative in this -++ // case) -++ stackSize += Frame.SIZE[opcode]; -++ addSuccessor(stackSize, label); -++ } -++ } -++ } -++ // adds the instruction to the bytecode of the method -++ if ((label.status & Label.RESOLVED) != 0 -++ && label.position - code.length < Short.MIN_VALUE) { -++ /* -++ * case of a backward jump with an offset < -32768. In this case we -++ * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx -++ * <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is the -++ * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where <l'> -++ * designates the instruction just after the GOTO_W. -++ */ -++ if (opcode == Opcodes.GOTO) { -++ code.putByte(200); // GOTO_W -++ } else if (opcode == Opcodes.JSR) { -++ code.putByte(201); // JSR_W -++ } else { -++ // if the IF instruction is transformed into IFNOT GOTO_W the -++ // next instruction becomes the target of the IFNOT instruction -++ if (nextInsn != null) { -++ nextInsn.status |= Label.TARGET; -++ } -++ code.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 -++ : opcode ^ 1); -++ code.putShort(8); // jump offset -++ code.putByte(200); // GOTO_W -++ } -++ label.put(this, code, code.length - 1, true); -++ } else { -++ /* -++ * case of a backward jump with an offset >= -32768, or of a forward -++ * jump with, of course, an unknown offset. In these cases we store -++ * the offset in 2 bytes (which will be increased in -++ * resizeInstructions, if needed). -++ */ -++ code.putByte(opcode); -++ label.put(this, code, code.length - 1, false); -++ } -++ if (currentBlock != null) { -++ if (nextInsn != null) { -++ // if the jump instruction is not a GOTO, the next instruction -++ // is also a successor of this instruction. Calling visitLabel -++ // adds the label of this next instruction as a successor of the -++ // current block, and starts a new basic block -++ visitLabel(nextInsn); -++ } -++ if (opcode == Opcodes.GOTO) { -++ noSuccessor(); -++ } -++ } -++ } -++ -++ @Override -++ public void visitLabel(final Label label) { -++ // resolves previous forward references to label, if any -++ resize |= label.resolve(this, code.length, code.data); -++ // updates currentBlock -++ if ((label.status & Label.DEBUG) != 0) { -++ return; -++ } -++ if (compute == FRAMES) { -++ if (currentBlock != null) { -++ if (label.position == currentBlock.position) { -++ // successive labels, do not start a new basic block -++ currentBlock.status |= (label.status & Label.TARGET); -++ label.frame = currentBlock.frame; -++ return; -++ } -++ // ends current block (with one new successor) -++ addSuccessor(Edge.NORMAL, label); -++ } -++ // begins a new current block -++ currentBlock = label; -++ if (label.frame == null) { -++ label.frame = new Frame(); -++ label.frame.owner = label; -++ } -++ // updates the basic block list -++ if (previousBlock != null) { -++ if (label.position == previousBlock.position) { -++ previousBlock.status |= (label.status & Label.TARGET); -++ label.frame = previousBlock.frame; -++ currentBlock = previousBlock; -++ return; -++ } -++ previousBlock.successor = label; -++ } -++ previousBlock = label; -++ } else if (compute == MAXS) { -++ if (currentBlock != null) { -++ // ends current block (with one new successor) -++ currentBlock.outputStackMax = maxStackSize; -++ addSuccessor(stackSize, label); -++ } -++ // begins a new current block -++ currentBlock = label; -++ // resets the relative current and max stack sizes -++ stackSize = 0; -++ maxStackSize = 0; -++ // updates the basic block list -++ if (previousBlock != null) { -++ previousBlock.successor = label; -++ } -++ previousBlock = label; -++ } -++ } -++ -++ @Override -++ public void visitLdcInsn(final Object cst) { -++ lastCodeOffset = code.length; -++ Item i = cw.newConstItem(cst); -++ // Label currentBlock = this.currentBlock; -++ if (currentBlock != null) { -++ if (compute == FRAMES) { -++ currentBlock.frame.execute(Opcodes.LDC, 0, cw, i); -++ } else { -++ int size; -++ // computes the stack size variation -++ if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) { -++ size = stackSize + 2; -++ } else { -++ size = stackSize + 1; -++ } -++ // updates current and max stack sizes -++ if (size > maxStackSize) { -++ maxStackSize = size; -++ } -++ stackSize = size; -++ } -++ } -++ // adds the instruction to the bytecode of the method -++ int index = i.index; -++ if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) { -++ code.put12(20 /* LDC2_W */, index); -++ } else if (index >= 256) { -++ code.put12(19 /* LDC_W */, index); -++ } else { -++ code.put11(Opcodes.LDC, index); -++ } -++ } -++ -++ @Override -++ public void visitIincInsn(final int var, final int increment) { -++ lastCodeOffset = code.length; -++ if (currentBlock != null) { -++ if (compute == FRAMES) { -++ currentBlock.frame.execute(Opcodes.IINC, var, null, null); -++ } -++ } -++ if (compute != NOTHING) { -++ // updates max locals -++ int n = var + 1; -++ if (n > maxLocals) { -++ maxLocals = n; -++ } -++ } -++ // adds the instruction to the bytecode of the method -++ if ((var > 255) || (increment > 127) || (increment < -128)) { -++ code.putByte(196 /* WIDE */).put12(Opcodes.IINC, var) -++ .putShort(increment); -++ } else { -++ code.putByte(Opcodes.IINC).put11(var, increment); -++ } -++ } -++ -++ @Override -++ public void visitTableSwitchInsn(final int min, final int max, -++ final Label dflt, final Label... labels) { -++ lastCodeOffset = code.length; -++ // adds the instruction to the bytecode of the method -++ int source = code.length; -++ code.putByte(Opcodes.TABLESWITCH); -++ code.putByteArray(null, 0, (4 - code.length % 4) % 4); -++ dflt.put(this, code, source, true); -++ code.putInt(min).putInt(max); -++ for (int i = 0; i < labels.length; ++i) { -++ labels[i].put(this, code, source, true); -++ } -++ // updates currentBlock -++ visitSwitchInsn(dflt, labels); -++ } -++ -++ @Override -++ public void visitLookupSwitchInsn(final Label dflt, final int[] keys, -++ final Label[] labels) { -++ lastCodeOffset = code.length; -++ // adds the instruction to the bytecode of the method -++ int source = code.length; -++ code.putByte(Opcodes.LOOKUPSWITCH); -++ code.putByteArray(null, 0, (4 - code.length % 4) % 4); -++ dflt.put(this, code, source, true); -++ code.putInt(labels.length); -++ for (int i = 0; i < labels.length; ++i) { -++ code.putInt(keys[i]); -++ labels[i].put(this, code, source, true); -++ } -++ // updates currentBlock -++ visitSwitchInsn(dflt, labels); -++ } -++ -++ private void visitSwitchInsn(final Label dflt, final Label[] labels) { -++ // Label currentBlock = this.currentBlock; -++ if (currentBlock != null) { -++ if (compute == FRAMES) { -++ currentBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0, null, null); -++ // adds current block successors -++ addSuccessor(Edge.NORMAL, dflt); -++ dflt.getFirst().status |= Label.TARGET; -++ for (int i = 0; i < labels.length; ++i) { -++ addSuccessor(Edge.NORMAL, labels[i]); -++ labels[i].getFirst().status |= Label.TARGET; -++ } -++ } else { -++ // updates current stack size (max stack size unchanged) -++ --stackSize; -++ // adds current block successors -++ addSuccessor(stackSize, dflt); -++ for (int i = 0; i < labels.length; ++i) { -++ addSuccessor(stackSize, labels[i]); -++ } -++ } -++ // ends current block -++ noSuccessor(); -++ } -++ } -++ -++ @Override -++ public void visitMultiANewArrayInsn(final String desc, final int dims) { -++ lastCodeOffset = code.length; -++ Item i = cw.newClassItem(desc); -++ // Label currentBlock = this.currentBlock; -++ if (currentBlock != null) { -++ if (compute == FRAMES) { -++ currentBlock.frame.execute(Opcodes.MULTIANEWARRAY, dims, cw, i); -++ } else { -++ // updates current stack size (max stack size unchanged because -++ // stack size variation always negative or null) -++ stackSize += 1 - dims; -++ } -++ } -++ // adds the instruction to the bytecode of the method -++ code.put12(Opcodes.MULTIANEWARRAY, i.index).putByte(dims); -++ } -++ -++ @Override -++ public AnnotationVisitor visitInsnAnnotation(int typeRef, -++ TypePath typePath, String desc, boolean visible) { -++ if (!ClassReader.ANNOTATIONS) { -++ return null; -++ } -++ ByteVector bv = new ByteVector(); -++ // write target_type and target_info -++ typeRef = (typeRef & 0xFF0000FF) | (lastCodeOffset << 8); -++ AnnotationWriter.putTarget(typeRef, typePath, bv); -++ // write type, and reserve space for values count -++ bv.putShort(cw.newUTF8(desc)).putShort(0); -++ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, -++ bv.length - 2); -++ if (visible) { -++ aw.next = ctanns; -++ ctanns = aw; -++ } else { -++ aw.next = ictanns; -++ ictanns = aw; -++ } -++ return aw; -++ } -++ -++ @Override -++ public void visitTryCatchBlock(final Label start, final Label end, -++ final Label handler, final String type) { -++ ++handlerCount; -++ Handler h = new Handler(); -++ h.start = start; -++ h.end = end; -++ h.handler = handler; -++ h.desc = type; -++ h.type = type != null ? cw.newClass(type) : 0; -++ if (lastHandler == null) { -++ firstHandler = h; -++ } else { -++ lastHandler.next = h; -++ } -++ lastHandler = h; -++ } -++ -++ @Override -++ public AnnotationVisitor visitTryCatchAnnotation(int typeRef, -++ TypePath typePath, String desc, boolean visible) { -++ if (!ClassReader.ANNOTATIONS) { -++ return null; -++ } -++ ByteVector bv = new ByteVector(); -++ // write target_type and target_info -++ AnnotationWriter.putTarget(typeRef, typePath, bv); -++ // write type, and reserve space for values count -++ bv.putShort(cw.newUTF8(desc)).putShort(0); -++ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, -++ bv.length - 2); -++ if (visible) { -++ aw.next = ctanns; -++ ctanns = aw; -++ } else { -++ aw.next = ictanns; -++ ictanns = aw; -++ } -++ return aw; -++ } -++ -++ @Override -++ public void visitLocalVariable(final String name, final String desc, -++ final String signature, final Label start, final Label end, -++ final int index) { -++ if (signature != null) { -++ if (localVarType == null) { -++ localVarType = new ByteVector(); -++ } -++ ++localVarTypeCount; -++ localVarType.putShort(start.position) -++ .putShort(end.position - start.position) -++ .putShort(cw.newUTF8(name)).putShort(cw.newUTF8(signature)) -++ .putShort(index); -++ } -++ if (localVar == null) { -++ localVar = new ByteVector(); -++ } -++ ++localVarCount; -++ localVar.putShort(start.position) -++ .putShort(end.position - start.position) -++ .putShort(cw.newUTF8(name)).putShort(cw.newUTF8(desc)) -++ .putShort(index); -++ if (compute != NOTHING) { -++ // updates max locals -++ char c = desc.charAt(0); -++ int n = index + (c == 'J' || c == 'D' ? 2 : 1); -++ if (n > maxLocals) { -++ maxLocals = n; -++ } -++ } -++ } -++ -++ @Override -++ public AnnotationVisitor visitLocalVariableAnnotation(int typeRef, -++ TypePath typePath, Label[] start, Label[] end, int[] index, -++ String desc, boolean visible) { -++ if (!ClassReader.ANNOTATIONS) { -++ return null; -++ } -++ ByteVector bv = new ByteVector(); -++ // write target_type and target_info -++ bv.putByte(typeRef >>> 24).putShort(start.length); -++ for (int i = 0; i < start.length; ++i) { -++ bv.putShort(start[i].position) -++ .putShort(end[i].position - start[i].position) -++ .putShort(index[i]); -++ } -++ if (typePath == null) { -++ bv.putByte(0); -++ } else { -++ int length = typePath.b[typePath.offset] * 2 + 1; -++ bv.putByteArray(typePath.b, typePath.offset, length); -++ } -++ // write type, and reserve space for values count -++ bv.putShort(cw.newUTF8(desc)).putShort(0); -++ AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, -++ bv.length - 2); -++ if (visible) { -++ aw.next = ctanns; -++ ctanns = aw; -++ } else { -++ aw.next = ictanns; -++ ictanns = aw; -++ } -++ return aw; -++ } -++ -++ @Override -++ public void visitLineNumber(final int line, final Label start) { -++ if (lineNumber == null) { -++ lineNumber = new ByteVector(); -++ } -++ ++lineNumberCount; -++ lineNumber.putShort(start.position); -++ lineNumber.putShort(line); -++ } -++ -++ @Override -++ public void visitMaxs(final int maxStack, final int maxLocals) { -++ if (resize) { -++ // replaces the temporary jump opcodes introduced by Label.resolve. -++ if (ClassReader.RESIZE) { -++ resizeInstructions(); -++ } else { -++ throw new RuntimeException("Method code too large!"); -++ } -++ } -++ if (ClassReader.FRAMES && compute == FRAMES) { -++ // completes the control flow graph with exception handler blocks -++ Handler handler = firstHandler; -++ while (handler != null) { -++ Label l = handler.start.getFirst(); -++ Label h = handler.handler.getFirst(); -++ Label e = handler.end.getFirst(); -++ // computes the kind of the edges to 'h' -++ String t = handler.desc == null ? "java/lang/Throwable" -++ : handler.desc; -++ int kind = Frame.OBJECT | cw.addType(t); -++ // h is an exception handler -++ h.status |= Label.TARGET; -++ // adds 'h' as a successor of labels between 'start' and 'end' -++ while (l != e) { -++ // creates an edge to 'h' -++ Edge b = new Edge(); -++ b.info = kind; -++ b.successor = h; -++ // adds it to the successors of 'l' -++ b.next = l.successors; -++ l.successors = b; -++ // goes to the next label -++ l = l.successor; -++ } -++ handler = handler.next; -++ } -++ -++ // creates and visits the first (implicit) frame -++ Frame f = labels.frame; -++ Type[] args = Type.getArgumentTypes(descriptor); -++ f.initInputFrame(cw, access, args, this.maxLocals); -++ visitFrame(f); -++ -++ /* -++ * fix point algorithm: mark the first basic block as 'changed' -++ * (i.e. put it in the 'changed' list) and, while there are changed -++ * basic blocks, choose one, mark it as unchanged, and update its -++ * successors (which can be changed in the process). -++ */ -++ int max = 0; -++ Label changed = labels; -++ while (changed != null) { -++ // removes a basic block from the list of changed basic blocks -++ Label l = changed; -++ changed = changed.next; -++ l.next = null; -++ f = l.frame; -++ // a reachable jump target must be stored in the stack map -++ if ((l.status & Label.TARGET) != 0) { -++ l.status |= Label.STORE; -++ } -++ // all visited labels are reachable, by definition -++ l.status |= Label.REACHABLE; -++ // updates the (absolute) maximum stack size -++ int blockMax = f.inputStack.length + l.outputStackMax; -++ if (blockMax > max) { -++ max = blockMax; -++ } -++ // updates the successors of the current basic block -++ Edge e = l.successors; -++ while (e != null) { -++ Label n = e.successor.getFirst(); -++ boolean change = f.merge(cw, n.frame, e.info); -++ if (change && n.next == null) { -++ // if n has changed and is not already in the 'changed' -++ // list, adds it to this list -++ n.next = changed; -++ changed = n; -++ } -++ e = e.next; -++ } -++ } -++ -++ // visits all the frames that must be stored in the stack map -++ Label l = labels; -++ while (l != null) { -++ f = l.frame; -++ if ((l.status & Label.STORE) != 0) { -++ visitFrame(f); -++ } -++ if ((l.status & Label.REACHABLE) == 0) { -++ // finds start and end of dead basic block -++ Label k = l.successor; -++ int start = l.position; -++ int end = (k == null ? code.length : k.position) - 1; -++ // if non empty basic block -++ if (end >= start) { -++ max = Math.max(max, 1); -++ // replaces instructions with NOP ... NOP ATHROW -++ for (int i = start; i < end; ++i) { -++ code.data[i] = Opcodes.NOP; -++ } -++ code.data[end] = (byte) Opcodes.ATHROW; -++ // emits a frame for this unreachable block -++ int frameIndex = startFrame(start, 0, 1); -++ frame[frameIndex] = Frame.OBJECT -++ | cw.addType("java/lang/Throwable"); -++ endFrame(); -++ // removes the start-end range from the exception -++ // handlers -++ firstHandler = Handler.remove(firstHandler, l, k); -++ } -++ } -++ l = l.successor; -++ } -++ -++ handler = firstHandler; -++ handlerCount = 0; -++ while (handler != null) { -++ handlerCount += 1; -++ handler = handler.next; -++ } -++ -++ this.maxStack = max; -++ } else if (compute == MAXS) { -++ // completes the control flow graph with exception handler blocks -++ Handler handler = firstHandler; -++ while (handler != null) { -++ Label l = handler.start; -++ Label h = handler.handler; -++ Label e = handler.end; -++ // adds 'h' as a successor of labels between 'start' and 'end' -++ while (l != e) { -++ // creates an edge to 'h' -++ Edge b = new Edge(); -++ b.info = Edge.EXCEPTION; -++ b.successor = h; -++ // adds it to the successors of 'l' -++ if ((l.status & Label.JSR) == 0) { -++ b.next = l.successors; -++ l.successors = b; -++ } else { -++ // if l is a JSR block, adds b after the first two edges -++ // to preserve the hypothesis about JSR block successors -++ // order (see {@link #visitJumpInsn}) -++ b.next = l.successors.next.next; -++ l.successors.next.next = b; -++ } -++ // goes to the next label -++ l = l.successor; -++ } -++ handler = handler.next; -++ } -++ -++ if (subroutines > 0) { -++ // completes the control flow graph with the RET successors -++ /* -++ * first step: finds the subroutines. This step determines, for -++ * each basic block, to which subroutine(s) it belongs. -++ */ -++ // finds the basic blocks that belong to the "main" subroutine -++ int id = 0; -++ labels.visitSubroutine(null, 1, subroutines); -++ // finds the basic blocks that belong to the real subroutines -++ Label l = labels; -++ while (l != null) { -++ if ((l.status & Label.JSR) != 0) { -++ // the subroutine is defined by l's TARGET, not by l -++ Label subroutine = l.successors.next.successor; -++ // if this subroutine has not been visited yet... -++ if ((subroutine.status & Label.VISITED) == 0) { -++ // ...assigns it a new id and finds its basic blocks -++ id += 1; -++ subroutine.visitSubroutine(null, (id / 32L) << 32 -++ | (1L << (id % 32)), subroutines); -++ } -++ } -++ l = l.successor; -++ } -++ // second step: finds the successors of RET blocks -++ l = labels; -++ while (l != null) { -++ if ((l.status & Label.JSR) != 0) { -++ Label L = labels; -++ while (L != null) { -++ L.status &= ~Label.VISITED2; -++ L = L.successor; -++ } -++ // the subroutine is defined by l's TARGET, not by l -++ Label subroutine = l.successors.next.successor; -++ subroutine.visitSubroutine(l, 0, subroutines); -++ } -++ l = l.successor; -++ } -++ } -++ -++ /* -++ * control flow analysis algorithm: while the block stack is not -++ * empty, pop a block from this stack, update the max stack size, -++ * compute the true (non relative) begin stack size of the -++ * successors of this block, and push these successors onto the -++ * stack (unless they have already been pushed onto the stack). -++ * Note: by hypothesis, the {@link Label#inputStackTop} of the -++ * blocks in the block stack are the true (non relative) beginning -++ * stack sizes of these blocks. -++ */ -++ int max = 0; -++ Label stack = labels; -++ while (stack != null) { -++ // pops a block from the stack -++ Label l = stack; -++ stack = stack.next; -++ // computes the true (non relative) max stack size of this block -++ int start = l.inputStackTop; -++ int blockMax = start + l.outputStackMax; -++ // updates the global max stack size -++ if (blockMax > max) { -++ max = blockMax; -++ } -++ // analyzes the successors of the block -++ Edge b = l.successors; -++ if ((l.status & Label.JSR) != 0) { -++ // ignores the first edge of JSR blocks (virtual successor) -++ b = b.next; -++ } -++ while (b != null) { -++ l = b.successor; -++ // if this successor has not already been pushed... -++ if ((l.status & Label.PUSHED) == 0) { -++ // computes its true beginning stack size... -++ l.inputStackTop = b.info == Edge.EXCEPTION ? 1 : start -++ + b.info; -++ // ...and pushes it onto the stack -++ l.status |= Label.PUSHED; -++ l.next = stack; -++ stack = l; -++ } -++ b = b.next; -++ } -++ } -++ this.maxStack = Math.max(maxStack, max); -++ } else { -++ this.maxStack = maxStack; -++ this.maxLocals = maxLocals; -++ } -++ } -++ -++ @Override -++ public void visitEnd() { -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Utility methods: control flow analysis algorithm -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Adds a successor to the {@link #currentBlock currentBlock} block. -++ * -++ * @param info -++ * information about the control flow edge to be added. -++ * @param successor -++ * the successor block to be added to the current block. -++ */ -++ private void addSuccessor(final int info, final Label successor) { -++ // creates and initializes an Edge object... -++ Edge b = new Edge(); -++ b.info = info; -++ b.successor = successor; -++ // ...and adds it to the successor list of the currentBlock block -++ b.next = currentBlock.successors; -++ currentBlock.successors = b; -++ } -++ -++ /** -++ * Ends the current basic block. This method must be used in the case where -++ * the current basic block does not have any successor. -++ */ -++ private void noSuccessor() { -++ if (compute == FRAMES) { -++ Label l = new Label(); -++ l.frame = new Frame(); -++ l.frame.owner = l; -++ l.resolve(this, code.length, code.data); -++ previousBlock.successor = l; -++ previousBlock = l; -++ } else { -++ currentBlock.outputStackMax = maxStackSize; -++ } -++ currentBlock = null; -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Utility methods: stack map frames -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Visits a frame that has been computed from scratch. -++ * -++ * @param f -++ * the frame that must be visited. -++ */ -++ private void visitFrame(final Frame f) { -++ int i, t; -++ int nTop = 0; -++ int nLocal = 0; -++ int nStack = 0; -++ int[] locals = f.inputLocals; -++ int[] stacks = f.inputStack; -++ // computes the number of locals (ignores TOP types that are just after -++ // a LONG or a DOUBLE, and all trailing TOP types) -++ for (i = 0; i < locals.length; ++i) { -++ t = locals[i]; -++ if (t == Frame.TOP) { -++ ++nTop; -++ } else { -++ nLocal += nTop + 1; -++ nTop = 0; -++ } -++ if (t == Frame.LONG || t == Frame.DOUBLE) { -++ ++i; -++ } -++ } -++ // computes the stack size (ignores TOP types that are just after -++ // a LONG or a DOUBLE) -++ for (i = 0; i < stacks.length; ++i) { -++ t = stacks[i]; -++ ++nStack; -++ if (t == Frame.LONG || t == Frame.DOUBLE) { -++ ++i; -++ } -++ } -++ // visits the frame and its content -++ int frameIndex = startFrame(f.owner.position, nLocal, nStack); -++ for (i = 0; nLocal > 0; ++i, --nLocal) { -++ t = locals[i]; -++ frame[frameIndex++] = t; -++ if (t == Frame.LONG || t == Frame.DOUBLE) { -++ ++i; -++ } -++ } -++ for (i = 0; i < stacks.length; ++i) { -++ t = stacks[i]; -++ frame[frameIndex++] = t; -++ if (t == Frame.LONG || t == Frame.DOUBLE) { -++ ++i; -++ } -++ } -++ endFrame(); -++ } -++ -++ /** -++ * Visit the implicit first frame of this method. -++ */ -++ private void visitImplicitFirstFrame() { -++ // There can be at most descriptor.length() + 1 locals -++ int frameIndex = startFrame(0, descriptor.length() + 1, 0); -++ if ((access & Opcodes.ACC_STATIC) == 0) { -++ if ((access & ACC_CONSTRUCTOR) == 0) { -++ frame[frameIndex++] = Frame.OBJECT | cw.addType(cw.thisName); -++ } else { -++ frame[frameIndex++] = 6; // Opcodes.UNINITIALIZED_THIS; -++ } -++ } -++ int i = 1; -++ loop: while (true) { -++ int j = i; -++ switch (descriptor.charAt(i++)) { -++ case 'Z': -++ case 'C': -++ case 'B': -++ case 'S': -++ case 'I': -++ frame[frameIndex++] = 1; // Opcodes.INTEGER; -++ break; -++ case 'F': -++ frame[frameIndex++] = 2; // Opcodes.FLOAT; -++ break; -++ case 'J': -++ frame[frameIndex++] = 4; // Opcodes.LONG; -++ break; -++ case 'D': -++ frame[frameIndex++] = 3; // Opcodes.DOUBLE; -++ break; -++ case '[': -++ while (descriptor.charAt(i) == '[') { -++ ++i; -++ } -++ if (descriptor.charAt(i) == 'L') { -++ ++i; -++ while (descriptor.charAt(i) != ';') { -++ ++i; -++ } -++ } -++ frame[frameIndex++] = Frame.OBJECT -++ | cw.addType(descriptor.substring(j, ++i)); -++ break; -++ case 'L': -++ while (descriptor.charAt(i) != ';') { -++ ++i; -++ } -++ frame[frameIndex++] = Frame.OBJECT -++ | cw.addType(descriptor.substring(j + 1, i++)); -++ break; -++ default: -++ break loop; -++ } -++ } -++ frame[1] = frameIndex - 3; -++ endFrame(); -++ } -++ -++ /** -++ * Starts the visit of a stack map frame. -++ * -++ * @param offset -++ * the offset of the instruction to which the frame corresponds. -++ * @param nLocal -++ * the number of local variables in the frame. -++ * @param nStack -++ * the number of stack elements in the frame. -++ * @return the index of the next element to be written in this frame. -++ */ -++ private int startFrame(final int offset, final int nLocal, final int nStack) { -++ int n = 3 + nLocal + nStack; -++ if (frame == null || frame.length < n) { -++ frame = new int[n]; -++ } -++ frame[0] = offset; -++ frame[1] = nLocal; -++ frame[2] = nStack; -++ return 3; -++ } -++ -++ /** -++ * Checks if the visit of the current frame {@link #frame} is finished, and -++ * if yes, write it in the StackMapTable attribute. -++ */ -++ private void endFrame() { -++ if (previousFrame != null) { // do not write the first frame -++ if (stackMap == null) { -++ stackMap = new ByteVector(); -++ } -++ writeFrame(); -++ ++frameCount; -++ } -++ previousFrame = frame; -++ frame = null; -++ } -++ -++ /** -++ * Compress and writes the current frame {@link #frame} in the StackMapTable -++ * attribute. -++ */ -++ private void writeFrame() { -++ int clocalsSize = frame[1]; -++ int cstackSize = frame[2]; -++ if ((cw.version & 0xFFFF) < Opcodes.V1_6) { -++ stackMap.putShort(frame[0]).putShort(clocalsSize); -++ writeFrameTypes(3, 3 + clocalsSize); -++ stackMap.putShort(cstackSize); -++ writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize); -++ return; -++ } -++ int localsSize = previousFrame[1]; -++ int type = FULL_FRAME; -++ int k = 0; -++ int delta; -++ if (frameCount == 0) { -++ delta = frame[0]; -++ } else { -++ delta = frame[0] - previousFrame[0] - 1; -++ } -++ if (cstackSize == 0) { -++ k = clocalsSize - localsSize; -++ switch (k) { -++ case -3: -++ case -2: -++ case -1: -++ type = CHOP_FRAME; -++ localsSize = clocalsSize; -++ break; -++ case 0: -++ type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED; -++ break; -++ case 1: -++ case 2: -++ case 3: -++ type = APPEND_FRAME; -++ break; -++ } -++ } else if (clocalsSize == localsSize && cstackSize == 1) { -++ type = delta < 63 ? SAME_LOCALS_1_STACK_ITEM_FRAME -++ : SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED; -++ } -++ if (type != FULL_FRAME) { -++ // verify if locals are the same -++ int l = 3; -++ for (int j = 0; j < localsSize; j++) { -++ if (frame[l] != previousFrame[l]) { -++ type = FULL_FRAME; -++ break; -++ } -++ l++; -++ } -++ } -++ switch (type) { -++ case SAME_FRAME: -++ stackMap.putByte(delta); -++ break; -++ case SAME_LOCALS_1_STACK_ITEM_FRAME: -++ stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); -++ writeFrameTypes(3 + clocalsSize, 4 + clocalsSize); -++ break; -++ case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED: -++ stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED).putShort( -++ delta); -++ writeFrameTypes(3 + clocalsSize, 4 + clocalsSize); -++ break; -++ case SAME_FRAME_EXTENDED: -++ stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta); -++ break; -++ case CHOP_FRAME: -++ stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta); -++ break; -++ case APPEND_FRAME: -++ stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta); -++ writeFrameTypes(3 + localsSize, 3 + clocalsSize); -++ break; -++ // case FULL_FRAME: -++ default: -++ stackMap.putByte(FULL_FRAME).putShort(delta).putShort(clocalsSize); -++ writeFrameTypes(3, 3 + clocalsSize); -++ stackMap.putShort(cstackSize); -++ writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize); -++ } -++ } -++ -++ /** -++ * Writes some types of the current frame {@link #frame} into the -++ * StackMapTableAttribute. This method converts types from the format used -++ * in {@link Label} to the format used in StackMapTable attributes. In -++ * particular, it converts type table indexes to constant pool indexes. -++ * -++ * @param start -++ * index of the first type in {@link #frame} to write. -++ * @param end -++ * index of last type in {@link #frame} to write (exclusive). -++ */ -++ private void writeFrameTypes(final int start, final int end) { -++ for (int i = start; i < end; ++i) { -++ int t = frame[i]; -++ int d = t & Frame.DIM; -++ if (d == 0) { -++ int v = t & Frame.BASE_VALUE; -++ switch (t & Frame.BASE_KIND) { -++ case Frame.OBJECT: -++ stackMap.putByte(7).putShort( -++ cw.newClass(cw.typeTable[v].strVal1)); -++ break; -++ case Frame.UNINITIALIZED: -++ stackMap.putByte(8).putShort(cw.typeTable[v].intVal); -++ break; -++ default: -++ stackMap.putByte(v); -++ } -++ } else { -++ StringBuilder sb = new StringBuilder(); -++ d >>= 28; -++ while (d-- > 0) { -++ sb.append('['); -++ } -++ if ((t & Frame.BASE_KIND) == Frame.OBJECT) { -++ sb.append('L'); -++ sb.append(cw.typeTable[t & Frame.BASE_VALUE].strVal1); -++ sb.append(';'); -++ } else { -++ switch (t & 0xF) { -++ case 1: -++ sb.append('I'); -++ break; -++ case 2: -++ sb.append('F'); -++ break; -++ case 3: -++ sb.append('D'); -++ break; -++ case 9: -++ sb.append('Z'); -++ break; -++ case 10: -++ sb.append('B'); -++ break; -++ case 11: -++ sb.append('C'); -++ break; -++ case 12: -++ sb.append('S'); -++ break; -++ default: -++ sb.append('J'); -++ } -++ } -++ stackMap.putByte(7).putShort(cw.newClass(sb.toString())); -++ } -++ } -++ } -++ -++ private void writeFrameType(final Object type) { -++ if (type instanceof String) { -++ stackMap.putByte(7).putShort(cw.newClass((String) type)); -++ } else if (type instanceof Integer) { -++ stackMap.putByte(((Integer) type).intValue()); -++ } else { -++ stackMap.putByte(8).putShort(((Label) type).position); -++ } -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Utility methods: dump bytecode array -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Returns the size of the bytecode of this method. -++ * -++ * @return the size of the bytecode of this method. -++ */ -++ final int getSize() { -++ if (classReaderOffset != 0) { -++ return 6 + classReaderLength; -++ } -++ int size = 8; -++ if (code.length > 0) { -++ if (code.length > 65536) { -++ throw new RuntimeException("Method code too large!"); -++ } -++ cw.newUTF8("Code"); -++ size += 18 + code.length + 8 * handlerCount; -++ if (localVar != null) { -++ cw.newUTF8("LocalVariableTable"); -++ size += 8 + localVar.length; -++ } -++ if (localVarType != null) { -++ cw.newUTF8("LocalVariableTypeTable"); -++ size += 8 + localVarType.length; -++ } -++ if (lineNumber != null) { -++ cw.newUTF8("LineNumberTable"); -++ size += 8 + lineNumber.length; -++ } -++ if (stackMap != null) { -++ boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6; -++ cw.newUTF8(zip ? "StackMapTable" : "StackMap"); -++ size += 8 + stackMap.length; -++ } -++ if (ClassReader.ANNOTATIONS && ctanns != null) { -++ cw.newUTF8("RuntimeVisibleTypeAnnotations"); -++ size += 8 + ctanns.getSize(); -++ } -++ if (ClassReader.ANNOTATIONS && ictanns != null) { -++ cw.newUTF8("RuntimeInvisibleTypeAnnotations"); -++ size += 8 + ictanns.getSize(); -++ } -++ if (cattrs != null) { -++ size += cattrs.getSize(cw, code.data, code.length, maxStack, -++ maxLocals); -++ } -++ } -++ if (exceptionCount > 0) { -++ cw.newUTF8("Exceptions"); -++ size += 8 + 2 * exceptionCount; -++ } -++ if ((access & Opcodes.ACC_SYNTHETIC) != 0) { -++ if ((cw.version & 0xFFFF) < Opcodes.V1_5 -++ || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { -++ cw.newUTF8("Synthetic"); -++ size += 6; -++ } -++ } -++ if ((access & Opcodes.ACC_DEPRECATED) != 0) { -++ cw.newUTF8("Deprecated"); -++ size += 6; -++ } -++ if (ClassReader.SIGNATURES && signature != null) { -++ cw.newUTF8("Signature"); -++ cw.newUTF8(signature); -++ size += 8; -++ } -++ if (methodParameters != null) { -++ cw.newUTF8("MethodParameters"); -++ size += 7 + methodParameters.length; -++ } -++ if (ClassReader.ANNOTATIONS && annd != null) { -++ cw.newUTF8("AnnotationDefault"); -++ size += 6 + annd.length; -++ } -++ if (ClassReader.ANNOTATIONS && anns != null) { -++ cw.newUTF8("RuntimeVisibleAnnotations"); -++ size += 8 + anns.getSize(); -++ } -++ if (ClassReader.ANNOTATIONS && ianns != null) { -++ cw.newUTF8("RuntimeInvisibleAnnotations"); -++ size += 8 + ianns.getSize(); -++ } -++ if (ClassReader.ANNOTATIONS && tanns != null) { -++ cw.newUTF8("RuntimeVisibleTypeAnnotations"); -++ size += 8 + tanns.getSize(); -++ } -++ if (ClassReader.ANNOTATIONS && itanns != null) { -++ cw.newUTF8("RuntimeInvisibleTypeAnnotations"); -++ size += 8 + itanns.getSize(); -++ } -++ if (ClassReader.ANNOTATIONS && panns != null) { -++ cw.newUTF8("RuntimeVisibleParameterAnnotations"); -++ size += 7 + 2 * (panns.length - synthetics); -++ for (int i = panns.length - 1; i >= synthetics; --i) { -++ size += panns[i] == null ? 0 : panns[i].getSize(); -++ } -++ } -++ if (ClassReader.ANNOTATIONS && ipanns != null) { -++ cw.newUTF8("RuntimeInvisibleParameterAnnotations"); -++ size += 7 + 2 * (ipanns.length - synthetics); -++ for (int i = ipanns.length - 1; i >= synthetics; --i) { -++ size += ipanns[i] == null ? 0 : ipanns[i].getSize(); -++ } -++ } -++ if (attrs != null) { -++ size += attrs.getSize(cw, null, 0, -1, -1); -++ } -++ return size; -++ } -++ -++ /** -++ * Puts the bytecode of this method in the given byte vector. -++ * -++ * @param out -++ * the byte vector into which the bytecode of this method must be -++ * copied. -++ */ -++ final void put(final ByteVector out) { -++ final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC; -++ int mask = ACC_CONSTRUCTOR | Opcodes.ACC_DEPRECATED -++ | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE -++ | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR); -++ out.putShort(access & ~mask).putShort(name).putShort(desc); -++ if (classReaderOffset != 0) { -++ out.putByteArray(cw.cr.b, classReaderOffset, classReaderLength); -++ return; -++ } -++ int attributeCount = 0; -++ if (code.length > 0) { -++ ++attributeCount; -++ } -++ if (exceptionCount > 0) { -++ ++attributeCount; -++ } -++ if ((access & Opcodes.ACC_SYNTHETIC) != 0) { -++ if ((cw.version & 0xFFFF) < Opcodes.V1_5 -++ || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { -++ ++attributeCount; -++ } -++ } -++ if ((access & Opcodes.ACC_DEPRECATED) != 0) { -++ ++attributeCount; -++ } -++ if (ClassReader.SIGNATURES && signature != null) { -++ ++attributeCount; -++ } -++ if (methodParameters != null) { -++ ++attributeCount; -++ } -++ if (ClassReader.ANNOTATIONS && annd != null) { -++ ++attributeCount; -++ } -++ if (ClassReader.ANNOTATIONS && anns != null) { -++ ++attributeCount; -++ } -++ if (ClassReader.ANNOTATIONS && ianns != null) { -++ ++attributeCount; -++ } -++ if (ClassReader.ANNOTATIONS && tanns != null) { -++ ++attributeCount; -++ } -++ if (ClassReader.ANNOTATIONS && itanns != null) { -++ ++attributeCount; -++ } -++ if (ClassReader.ANNOTATIONS && panns != null) { -++ ++attributeCount; -++ } -++ if (ClassReader.ANNOTATIONS && ipanns != null) { -++ ++attributeCount; -++ } -++ if (attrs != null) { -++ attributeCount += attrs.getCount(); -++ } -++ out.putShort(attributeCount); -++ if (code.length > 0) { -++ int size = 12 + code.length + 8 * handlerCount; -++ if (localVar != null) { -++ size += 8 + localVar.length; -++ } -++ if (localVarType != null) { -++ size += 8 + localVarType.length; -++ } -++ if (lineNumber != null) { -++ size += 8 + lineNumber.length; -++ } -++ if (stackMap != null) { -++ size += 8 + stackMap.length; -++ } -++ if (ClassReader.ANNOTATIONS && ctanns != null) { -++ size += 8 + ctanns.getSize(); -++ } -++ if (ClassReader.ANNOTATIONS && ictanns != null) { -++ size += 8 + ictanns.getSize(); -++ } -++ if (cattrs != null) { -++ size += cattrs.getSize(cw, code.data, code.length, maxStack, -++ maxLocals); -++ } -++ out.putShort(cw.newUTF8("Code")).putInt(size); -++ out.putShort(maxStack).putShort(maxLocals); -++ out.putInt(code.length).putByteArray(code.data, 0, code.length); -++ out.putShort(handlerCount); -++ if (handlerCount > 0) { -++ Handler h = firstHandler; -++ while (h != null) { -++ out.putShort(h.start.position).putShort(h.end.position) -++ .putShort(h.handler.position).putShort(h.type); -++ h = h.next; -++ } -++ } -++ attributeCount = 0; -++ if (localVar != null) { -++ ++attributeCount; -++ } -++ if (localVarType != null) { -++ ++attributeCount; -++ } -++ if (lineNumber != null) { -++ ++attributeCount; -++ } -++ if (stackMap != null) { -++ ++attributeCount; -++ } -++ if (ClassReader.ANNOTATIONS && ctanns != null) { -++ ++attributeCount; -++ } -++ if (ClassReader.ANNOTATIONS && ictanns != null) { -++ ++attributeCount; -++ } -++ if (cattrs != null) { -++ attributeCount += cattrs.getCount(); -++ } -++ out.putShort(attributeCount); -++ if (localVar != null) { -++ out.putShort(cw.newUTF8("LocalVariableTable")); -++ out.putInt(localVar.length + 2).putShort(localVarCount); -++ out.putByteArray(localVar.data, 0, localVar.length); -++ } -++ if (localVarType != null) { -++ out.putShort(cw.newUTF8("LocalVariableTypeTable")); -++ out.putInt(localVarType.length + 2).putShort(localVarTypeCount); -++ out.putByteArray(localVarType.data, 0, localVarType.length); -++ } -++ if (lineNumber != null) { -++ out.putShort(cw.newUTF8("LineNumberTable")); -++ out.putInt(lineNumber.length + 2).putShort(lineNumberCount); -++ out.putByteArray(lineNumber.data, 0, lineNumber.length); -++ } -++ if (stackMap != null) { -++ boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6; -++ out.putShort(cw.newUTF8(zip ? "StackMapTable" : "StackMap")); -++ out.putInt(stackMap.length + 2).putShort(frameCount); -++ out.putByteArray(stackMap.data, 0, stackMap.length); -++ } -++ if (ClassReader.ANNOTATIONS && ctanns != null) { -++ out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations")); -++ ctanns.put(out); -++ } -++ if (ClassReader.ANNOTATIONS && ictanns != null) { -++ out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations")); -++ ictanns.put(out); -++ } -++ if (cattrs != null) { -++ cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out); -++ } -++ } -++ if (exceptionCount > 0) { -++ out.putShort(cw.newUTF8("Exceptions")).putInt( -++ 2 * exceptionCount + 2); -++ out.putShort(exceptionCount); -++ for (int i = 0; i < exceptionCount; ++i) { -++ out.putShort(exceptions[i]); -++ } -++ } -++ if ((access & Opcodes.ACC_SYNTHETIC) != 0) { -++ if ((cw.version & 0xFFFF) < Opcodes.V1_5 -++ || (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { -++ out.putShort(cw.newUTF8("Synthetic")).putInt(0); -++ } -++ } -++ if ((access & Opcodes.ACC_DEPRECATED) != 0) { -++ out.putShort(cw.newUTF8("Deprecated")).putInt(0); -++ } -++ if (ClassReader.SIGNATURES && signature != null) { -++ out.putShort(cw.newUTF8("Signature")).putInt(2) -++ .putShort(cw.newUTF8(signature)); -++ } -++ if (methodParameters != null) { -++ out.putShort(cw.newUTF8("MethodParameters")); -++ out.putInt(methodParameters.length + 1).putByte( -++ methodParametersCount); -++ out.putByteArray(methodParameters.data, 0, methodParameters.length); -++ } -++ if (ClassReader.ANNOTATIONS && annd != null) { -++ out.putShort(cw.newUTF8("AnnotationDefault")); -++ out.putInt(annd.length); -++ out.putByteArray(annd.data, 0, annd.length); -++ } -++ if (ClassReader.ANNOTATIONS && anns != null) { -++ out.putShort(cw.newUTF8("RuntimeVisibleAnnotations")); -++ anns.put(out); -++ } -++ if (ClassReader.ANNOTATIONS && ianns != null) { -++ out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations")); -++ ianns.put(out); -++ } -++ if (ClassReader.ANNOTATIONS && tanns != null) { -++ out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations")); -++ tanns.put(out); -++ } -++ if (ClassReader.ANNOTATIONS && itanns != null) { -++ out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations")); -++ itanns.put(out); -++ } -++ if (ClassReader.ANNOTATIONS && panns != null) { -++ out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations")); -++ AnnotationWriter.put(panns, synthetics, out); -++ } -++ if (ClassReader.ANNOTATIONS && ipanns != null) { -++ out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations")); -++ AnnotationWriter.put(ipanns, synthetics, out); -++ } -++ if (attrs != null) { -++ attrs.put(cw, null, 0, -1, -1, out); -++ } -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Utility methods: instruction resizing (used to handle GOTO_W and JSR_W) -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Resizes and replaces the temporary instructions inserted by -++ * {@link Label#resolve} for wide forward jumps, while keeping jump offsets -++ * and instruction addresses consistent. This may require to resize other -++ * existing instructions, or even to introduce new instructions: for -++ * example, increasing the size of an instruction by 2 at the middle of a -++ * method can increases the offset of an IFEQ instruction from 32766 to -++ * 32768, in which case IFEQ 32766 must be replaced with IFNEQ 8 GOTO_W -++ * 32765. This, in turn, may require to increase the size of another jump -++ * instruction, and so on... All these operations are handled automatically -++ * by this method. -++ * <p> -++ * <i>This method must be called after all the method that is being built -++ * has been visited</i>. In particular, the {@link Label Label} objects used -++ * to construct the method are no longer valid after this method has been -++ * called. -++ */ -++ private void resizeInstructions() { -++ byte[] b = code.data; // bytecode of the method -++ int u, v, label; // indexes in b -++ int i, j; // loop indexes -++ /* -++ * 1st step: As explained above, resizing an instruction may require to -++ * resize another one, which may require to resize yet another one, and -++ * so on. The first step of the algorithm consists in finding all the -++ * instructions that need to be resized, without modifying the code. -++ * This is done by the following "fix point" algorithm: -++ * -++ * Parse the code to find the jump instructions whose offset will need -++ * more than 2 bytes to be stored (the future offset is computed from -++ * the current offset and from the number of bytes that will be inserted -++ * or removed between the source and target instructions). For each such -++ * instruction, adds an entry in (a copy of) the indexes and sizes -++ * arrays (if this has not already been done in a previous iteration!). -++ * -++ * If at least one entry has been added during the previous step, go -++ * back to the beginning, otherwise stop. -++ * -++ * In fact the real algorithm is complicated by the fact that the size -++ * of TABLESWITCH and LOOKUPSWITCH instructions depends on their -++ * position in the bytecode (because of padding). In order to ensure the -++ * convergence of the algorithm, the number of bytes to be added or -++ * removed from these instructions is over estimated during the previous -++ * loop, and computed exactly only after the loop is finished (this -++ * requires another pass to parse the bytecode of the method). -++ */ -++ int[] allIndexes = new int[0]; // copy of indexes -++ int[] allSizes = new int[0]; // copy of sizes -++ boolean[] resize; // instructions to be resized -++ int newOffset; // future offset of a jump instruction -++ -++ resize = new boolean[code.length]; -++ -++ // 3 = loop again, 2 = loop ended, 1 = last pass, 0 = done -++ int state = 3; -++ do { -++ if (state == 3) { -++ state = 2; -++ } -++ u = 0; -++ while (u < b.length) { -++ int opcode = b[u] & 0xFF; // opcode of current instruction -++ int insert = 0; // bytes to be added after this instruction -++ -++ switch (ClassWriter.TYPE[opcode]) { -++ case ClassWriter.NOARG_INSN: -++ case ClassWriter.IMPLVAR_INSN: -++ u += 1; -++ break; -++ case ClassWriter.LABEL_INSN: -++ if (opcode > 201) { -++ // converts temporary opcodes 202 to 217, 218 and -++ // 219 to IFEQ ... JSR (inclusive), IFNULL and -++ // IFNONNULL -++ opcode = opcode < 218 ? opcode - 49 : opcode - 20; -++ label = u + readUnsignedShort(b, u + 1); -++ } else { -++ label = u + readShort(b, u + 1); -++ } -++ newOffset = getNewOffset(allIndexes, allSizes, u, label); -++ if (newOffset < Short.MIN_VALUE -++ || newOffset > Short.MAX_VALUE) { -++ if (!resize[u]) { -++ if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) { -++ // two additional bytes will be required to -++ // replace this GOTO or JSR instruction with -++ // a GOTO_W or a JSR_W -++ insert = 2; -++ } else { -++ // five additional bytes will be required to -++ // replace this IFxxx <l> instruction with -++ // IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx -++ // is the "opposite" opcode of IFxxx (i.e., -++ // IFNE for IFEQ) and where <l'> designates -++ // the instruction just after the GOTO_W. -++ insert = 5; -++ } -++ resize[u] = true; -++ } -++ } -++ u += 3; -++ break; -++ case ClassWriter.LABELW_INSN: -++ u += 5; -++ break; -++ case ClassWriter.TABL_INSN: -++ if (state == 1) { -++ // true number of bytes to be added (or removed) -++ // from this instruction = (future number of padding -++ // bytes - current number of padding byte) - -++ // previously over estimated variation = -++ // = ((3 - newOffset%4) - (3 - u%4)) - u%4 -++ // = (-newOffset%4 + u%4) - u%4 -++ // = -(newOffset & 3) -++ newOffset = getNewOffset(allIndexes, allSizes, 0, u); -++ insert = -(newOffset & 3); -++ } else if (!resize[u]) { -++ // over estimation of the number of bytes to be -++ // added to this instruction = 3 - current number -++ // of padding bytes = 3 - (3 - u%4) = u%4 = u & 3 -++ insert = u & 3; -++ resize[u] = true; -++ } -++ // skips instruction -++ u = u + 4 - (u & 3); -++ u += 4 * (readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12; -++ break; -++ case ClassWriter.LOOK_INSN: -++ if (state == 1) { -++ // like TABL_INSN -++ newOffset = getNewOffset(allIndexes, allSizes, 0, u); -++ insert = -(newOffset & 3); -++ } else if (!resize[u]) { -++ // like TABL_INSN -++ insert = u & 3; -++ resize[u] = true; -++ } -++ // skips instruction -++ u = u + 4 - (u & 3); -++ u += 8 * readInt(b, u + 4) + 8; -++ break; -++ case ClassWriter.WIDE_INSN: -++ opcode = b[u + 1] & 0xFF; -++ if (opcode == Opcodes.IINC) { -++ u += 6; -++ } else { -++ u += 4; -++ } -++ break; -++ case ClassWriter.VAR_INSN: -++ case ClassWriter.SBYTE_INSN: -++ case ClassWriter.LDC_INSN: -++ u += 2; -++ break; -++ case ClassWriter.SHORT_INSN: -++ case ClassWriter.LDCW_INSN: -++ case ClassWriter.FIELDORMETH_INSN: -++ case ClassWriter.TYPE_INSN: -++ case ClassWriter.IINC_INSN: -++ u += 3; -++ break; -++ case ClassWriter.ITFMETH_INSN: -++ case ClassWriter.INDYMETH_INSN: -++ u += 5; -++ break; -++ // case ClassWriter.MANA_INSN: -++ default: -++ u += 4; -++ break; -++ } -++ if (insert != 0) { -++ // adds a new (u, insert) entry in the allIndexes and -++ // allSizes arrays -++ int[] newIndexes = new int[allIndexes.length + 1]; -++ int[] newSizes = new int[allSizes.length + 1]; -++ System.arraycopy(allIndexes, 0, newIndexes, 0, -++ allIndexes.length); -++ System.arraycopy(allSizes, 0, newSizes, 0, allSizes.length); -++ newIndexes[allIndexes.length] = u; -++ newSizes[allSizes.length] = insert; -++ allIndexes = newIndexes; -++ allSizes = newSizes; -++ if (insert > 0) { -++ state = 3; -++ } -++ } -++ } -++ if (state < 3) { -++ --state; -++ } -++ } while (state != 0); -++ -++ // 2nd step: -++ // copies the bytecode of the method into a new bytevector, updates the -++ // offsets, and inserts (or removes) bytes as requested. -++ -++ ByteVector newCode = new ByteVector(code.length); -++ -++ u = 0; -++ while (u < code.length) { -++ int opcode = b[u] & 0xFF; -++ switch (ClassWriter.TYPE[opcode]) { -++ case ClassWriter.NOARG_INSN: -++ case ClassWriter.IMPLVAR_INSN: -++ newCode.putByte(opcode); -++ u += 1; -++ break; -++ case ClassWriter.LABEL_INSN: -++ if (opcode > 201) { -++ // changes temporary opcodes 202 to 217 (inclusive), 218 -++ // and 219 to IFEQ ... JSR (inclusive), IFNULL and -++ // IFNONNULL -++ opcode = opcode < 218 ? opcode - 49 : opcode - 20; -++ label = u + readUnsignedShort(b, u + 1); -++ } else { -++ label = u + readShort(b, u + 1); -++ } -++ newOffset = getNewOffset(allIndexes, allSizes, u, label); -++ if (resize[u]) { -++ // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx -++ // <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is -++ // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) -++ // and where <l'> designates the instruction just after -++ // the GOTO_W. -++ if (opcode == Opcodes.GOTO) { -++ newCode.putByte(200); // GOTO_W -++ } else if (opcode == Opcodes.JSR) { -++ newCode.putByte(201); // JSR_W -++ } else { -++ newCode.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 -++ : opcode ^ 1); -++ newCode.putShort(8); // jump offset -++ newCode.putByte(200); // GOTO_W -++ // newOffset now computed from start of GOTO_W -++ newOffset -= 3; -++ } -++ newCode.putInt(newOffset); -++ } else { -++ newCode.putByte(opcode); -++ newCode.putShort(newOffset); -++ } -++ u += 3; -++ break; -++ case ClassWriter.LABELW_INSN: -++ label = u + readInt(b, u + 1); -++ newOffset = getNewOffset(allIndexes, allSizes, u, label); -++ newCode.putByte(opcode); -++ newCode.putInt(newOffset); -++ u += 5; -++ break; -++ case ClassWriter.TABL_INSN: -++ // skips 0 to 3 padding bytes -++ v = u; -++ u = u + 4 - (v & 3); -++ // reads and copies instruction -++ newCode.putByte(Opcodes.TABLESWITCH); -++ newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4); -++ label = v + readInt(b, u); -++ u += 4; -++ newOffset = getNewOffset(allIndexes, allSizes, v, label); -++ newCode.putInt(newOffset); -++ j = readInt(b, u); -++ u += 4; -++ newCode.putInt(j); -++ j = readInt(b, u) - j + 1; -++ u += 4; -++ newCode.putInt(readInt(b, u - 4)); -++ for (; j > 0; --j) { -++ label = v + readInt(b, u); -++ u += 4; -++ newOffset = getNewOffset(allIndexes, allSizes, v, label); -++ newCode.putInt(newOffset); -++ } -++ break; -++ case ClassWriter.LOOK_INSN: -++ // skips 0 to 3 padding bytes -++ v = u; -++ u = u + 4 - (v & 3); -++ // reads and copies instruction -++ newCode.putByte(Opcodes.LOOKUPSWITCH); -++ newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4); -++ label = v + readInt(b, u); -++ u += 4; -++ newOffset = getNewOffset(allIndexes, allSizes, v, label); -++ newCode.putInt(newOffset); -++ j = readInt(b, u); -++ u += 4; -++ newCode.putInt(j); -++ for (; j > 0; --j) { -++ newCode.putInt(readInt(b, u)); -++ u += 4; -++ label = v + readInt(b, u); -++ u += 4; -++ newOffset = getNewOffset(allIndexes, allSizes, v, label); -++ newCode.putInt(newOffset); -++ } -++ break; -++ case ClassWriter.WIDE_INSN: -++ opcode = b[u + 1] & 0xFF; -++ if (opcode == Opcodes.IINC) { -++ newCode.putByteArray(b, u, 6); -++ u += 6; -++ } else { -++ newCode.putByteArray(b, u, 4); -++ u += 4; -++ } -++ break; -++ case ClassWriter.VAR_INSN: -++ case ClassWriter.SBYTE_INSN: -++ case ClassWriter.LDC_INSN: -++ newCode.putByteArray(b, u, 2); -++ u += 2; -++ break; -++ case ClassWriter.SHORT_INSN: -++ case ClassWriter.LDCW_INSN: -++ case ClassWriter.FIELDORMETH_INSN: -++ case ClassWriter.TYPE_INSN: -++ case ClassWriter.IINC_INSN: -++ newCode.putByteArray(b, u, 3); -++ u += 3; -++ break; -++ case ClassWriter.ITFMETH_INSN: -++ case ClassWriter.INDYMETH_INSN: -++ newCode.putByteArray(b, u, 5); -++ u += 5; -++ break; -++ // case MANA_INSN: -++ default: -++ newCode.putByteArray(b, u, 4); -++ u += 4; -++ break; -++ } -++ } -++ -++ // updates the stack map frame labels -++ if (compute == FRAMES) { -++ Label l = labels; -++ while (l != null) { -++ /* -++ * Detects the labels that are just after an IF instruction that -++ * has been resized with the IFNOT GOTO_W pattern. These labels -++ * are now the target of a jump instruction (the IFNOT -++ * instruction). Note that we need the original label position -++ * here. getNewOffset must therefore never have been called for -++ * this label. -++ */ -++ u = l.position - 3; -++ if (u >= 0 && resize[u]) { -++ l.status |= Label.TARGET; -++ } -++ getNewOffset(allIndexes, allSizes, l); -++ l = l.successor; -++ } -++ // Update the offsets in the uninitialized types -++ if (cw.typeTable != null) { -++ for (i = 0; i < cw.typeTable.length; ++i) { -++ Item item = cw.typeTable[i]; -++ if (item != null && item.type == ClassWriter.TYPE_UNINIT) { -++ item.intVal = getNewOffset(allIndexes, allSizes, 0, -++ item.intVal); -++ } -++ } -++ } -++ // The stack map frames are not serialized yet, so we don't need -++ // to update them. They will be serialized in visitMaxs. -++ } else if (frameCount > 0) { -++ /* -++ * Resizing an existing stack map frame table is really hard. Not -++ * only the table must be parsed to update the offets, but new -++ * frames may be needed for jump instructions that were inserted by -++ * this method. And updating the offsets or inserting frames can -++ * change the format of the following frames, in case of packed -++ * frames. In practice the whole table must be recomputed. For this -++ * the frames are marked as potentially invalid. This will cause the -++ * whole class to be reread and rewritten with the COMPUTE_FRAMES -++ * option (see the ClassWriter.toByteArray method). This is not very -++ * efficient but is much easier and requires much less code than any -++ * other method I can think of. -++ */ -++ cw.invalidFrames = true; -++ } -++ // updates the exception handler block labels -++ Handler h = firstHandler; -++ while (h != null) { -++ getNewOffset(allIndexes, allSizes, h.start); -++ getNewOffset(allIndexes, allSizes, h.end); -++ getNewOffset(allIndexes, allSizes, h.handler); -++ h = h.next; -++ } -++ // updates the instructions addresses in the -++ // local var and line number tables -++ for (i = 0; i < 2; ++i) { -++ ByteVector bv = i == 0 ? localVar : localVarType; -++ if (bv != null) { -++ b = bv.data; -++ u = 0; -++ while (u < bv.length) { -++ label = readUnsignedShort(b, u); -++ newOffset = getNewOffset(allIndexes, allSizes, 0, label); -++ writeShort(b, u, newOffset); -++ label += readUnsignedShort(b, u + 2); -++ newOffset = getNewOffset(allIndexes, allSizes, 0, label) -++ - newOffset; -++ writeShort(b, u + 2, newOffset); -++ u += 10; -++ } -++ } -++ } -++ if (lineNumber != null) { -++ b = lineNumber.data; -++ u = 0; -++ while (u < lineNumber.length) { -++ writeShort( -++ b, -++ u, -++ getNewOffset(allIndexes, allSizes, 0, -++ readUnsignedShort(b, u))); -++ u += 4; -++ } -++ } -++ // updates the labels of the other attributes -++ Attribute attr = cattrs; -++ while (attr != null) { -++ Label[] labels = attr.getLabels(); -++ if (labels != null) { -++ for (i = labels.length - 1; i >= 0; --i) { -++ getNewOffset(allIndexes, allSizes, labels[i]); -++ } -++ } -++ attr = attr.next; -++ } -++ -++ // replaces old bytecodes with new ones -++ code = newCode; -++ } -++ -++ /** -++ * Reads an unsigned short value in the given byte array. -++ * -++ * @param b -++ * a byte array. -++ * @param index -++ * the start index of the value to be read. -++ * @return the read value. -++ */ -++ static int readUnsignedShort(final byte[] b, final int index) { -++ return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF); -++ } -++ -++ /** -++ * Reads a signed short value in the given byte array. -++ * -++ * @param b -++ * a byte array. -++ * @param index -++ * the start index of the value to be read. -++ * @return the read value. -++ */ -++ static short readShort(final byte[] b, final int index) { -++ return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF)); -++ } -++ -++ /** -++ * Reads a signed int value in the given byte array. -++ * -++ * @param b -++ * a byte array. -++ * @param index -++ * the start index of the value to be read. -++ * @return the read value. -++ */ -++ static int readInt(final byte[] b, final int index) { -++ return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16) -++ | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF); -++ } -++ -++ /** -++ * Writes a short value in the given byte array. -++ * -++ * @param b -++ * a byte array. -++ * @param index -++ * where the first byte of the short value must be written. -++ * @param s -++ * the value to be written in the given byte array. -++ */ -++ static void writeShort(final byte[] b, final int index, final int s) { -++ b[index] = (byte) (s >>> 8); -++ b[index + 1] = (byte) s; -++ } -++ -++ /** -++ * Computes the future value of a bytecode offset. -++ * <p> -++ * Note: it is possible to have several entries for the same instruction in -++ * the <tt>indexes</tt> and <tt>sizes</tt>: two entries (index=a,size=b) and -++ * (index=a,size=b') are equivalent to a single entry (index=a,size=b+b'). -++ * -++ * @param indexes -++ * current positions of the instructions to be resized. Each -++ * instruction must be designated by the index of its <i>last</i> -++ * byte, plus one (or, in other words, by the index of the -++ * <i>first</i> byte of the <i>next</i> instruction). -++ * @param sizes -++ * the number of bytes to be <i>added</i> to the above -++ * instructions. More precisely, for each i < <tt>len</tt>, -++ * <tt>sizes</tt>[i] bytes will be added at the end of the -++ * instruction designated by <tt>indexes</tt>[i] or, if -++ * <tt>sizes</tt>[i] is negative, the <i>last</i> | -++ * <tt>sizes[i]</tt>| bytes of the instruction will be removed -++ * (the instruction size <i>must not</i> become negative or -++ * null). -++ * @param begin -++ * index of the first byte of the source instruction. -++ * @param end -++ * index of the first byte of the target instruction. -++ * @return the future value of the given bytecode offset. -++ */ -++ static int getNewOffset(final int[] indexes, final int[] sizes, -++ final int begin, final int end) { -++ int offset = end - begin; -++ for (int i = 0; i < indexes.length; ++i) { -++ if (begin < indexes[i] && indexes[i] <= end) { -++ // forward jump -++ offset += sizes[i]; -++ } else if (end < indexes[i] && indexes[i] <= begin) { -++ // backward jump -++ offset -= sizes[i]; -++ } -++ } -++ return offset; -++ } -++ -++ /** -++ * Updates the offset of the given label. -++ * -++ * @param indexes -++ * current positions of the instructions to be resized. Each -++ * instruction must be designated by the index of its <i>last</i> -++ * byte, plus one (or, in other words, by the index of the -++ * <i>first</i> byte of the <i>next</i> instruction). -++ * @param sizes -++ * the number of bytes to be <i>added</i> to the above -++ * instructions. More precisely, for each i < <tt>len</tt>, -++ * <tt>sizes</tt>[i] bytes will be added at the end of the -++ * instruction designated by <tt>indexes</tt>[i] or, if -++ * <tt>sizes</tt>[i] is negative, the <i>last</i> | -++ * <tt>sizes[i]</tt>| bytes of the instruction will be removed -++ * (the instruction size <i>must not</i> become negative or -++ * null). -++ * @param label -++ * the label whose offset must be updated. -++ */ -++ static void getNewOffset(final int[] indexes, final int[] sizes, -++ final Label label) { -++ if ((label.status & Label.RESIZED) == 0) { -++ label.position = getNewOffset(indexes, sizes, 0, label.position); -++ label.status |= Label.RESIZED; -++ } -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/Opcodes.java b/contrib/asm/src/org/objectweb/asm/Opcodes.java -+new file mode 100644 -+index 0000000..e5c2b33 -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/Opcodes.java -+@@ -0,0 +1,361 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++/** -++ * Defines the JVM opcodes, access flags and array type codes. This interface -++ * does not define all the JVM opcodes because some opcodes are automatically -++ * handled. For example, the xLOAD and xSTORE opcodes are automatically replaced -++ * by xLOAD_n and xSTORE_n opcodes when possible. The xLOAD_n and xSTORE_n -++ * opcodes are therefore not defined in this interface. Likewise for LDC, -++ * automatically replaced by LDC_W or LDC2_W when necessary, WIDE, GOTO_W and -++ * JSR_W. -++ * -++ * @author Eric Bruneton -++ * @author Eugene Kuleshov -++ */ -++public interface Opcodes { -++ -++ // ASM API versions -++ -++ int ASM4 = 4 << 16 | 0 << 8 | 0; -++ int ASM5 = 5 << 16 | 0 << 8 | 0; -++ -++ // versions -++ -++ int V1_1 = 3 << 16 | 45; -++ int V1_2 = 0 << 16 | 46; -++ int V1_3 = 0 << 16 | 47; -++ int V1_4 = 0 << 16 | 48; -++ int V1_5 = 0 << 16 | 49; -++ int V1_6 = 0 << 16 | 50; -++ int V1_7 = 0 << 16 | 51; -++ int V1_8 = 0 << 16 | 52; -++ -++ // access flags -++ -++ int ACC_PUBLIC = 0x0001; // class, field, method -++ int ACC_PRIVATE = 0x0002; // class, field, method -++ int ACC_PROTECTED = 0x0004; // class, field, method -++ int ACC_STATIC = 0x0008; // field, method -++ int ACC_FINAL = 0x0010; // class, field, method, parameter -++ int ACC_SUPER = 0x0020; // class -++ int ACC_SYNCHRONIZED = 0x0020; // method -++ int ACC_VOLATILE = 0x0040; // field -++ int ACC_BRIDGE = 0x0040; // method -++ int ACC_VARARGS = 0x0080; // method -++ int ACC_TRANSIENT = 0x0080; // field -++ int ACC_NATIVE = 0x0100; // method -++ int ACC_INTERFACE = 0x0200; // class -++ int ACC_ABSTRACT = 0x0400; // class, method -++ int ACC_STRICT = 0x0800; // method -++ int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter -++ int ACC_ANNOTATION = 0x2000; // class -++ int ACC_ENUM = 0x4000; // class(?) field inner -++ int ACC_MANDATED = 0x8000; // parameter -++ -++ // ASM specific pseudo access flags -++ -++ int ACC_DEPRECATED = 0x20000; // class, field, method -++ -++ // types for NEWARRAY -++ -++ int T_BOOLEAN = 4; -++ int T_CHAR = 5; -++ int T_FLOAT = 6; -++ int T_DOUBLE = 7; -++ int T_BYTE = 8; -++ int T_SHORT = 9; -++ int T_INT = 10; -++ int T_LONG = 11; -++ -++ // tags for Handle -++ -++ int H_GETFIELD = 1; -++ int H_GETSTATIC = 2; -++ int H_PUTFIELD = 3; -++ int H_PUTSTATIC = 4; -++ int H_INVOKEVIRTUAL = 5; -++ int H_INVOKESTATIC = 6; -++ int H_INVOKESPECIAL = 7; -++ int H_NEWINVOKESPECIAL = 8; -++ int H_INVOKEINTERFACE = 9; -++ -++ // stack map frame types -++ -++ /** -++ * Represents an expanded frame. See {@link ClassReader#EXPAND_FRAMES}. -++ */ -++ int F_NEW = -1; -++ -++ /** -++ * Represents a compressed frame with complete frame data. -++ */ -++ int F_FULL = 0; -++ -++ /** -++ * Represents a compressed frame where locals are the same as the locals in -++ * the previous frame, except that additional 1-3 locals are defined, and -++ * with an empty stack. -++ */ -++ int F_APPEND = 1; -++ -++ /** -++ * Represents a compressed frame where locals are the same as the locals in -++ * the previous frame, except that the last 1-3 locals are absent and with -++ * an empty stack. -++ */ -++ int F_CHOP = 2; -++ -++ /** -++ * Represents a compressed frame with exactly the same locals as the -++ * previous frame and with an empty stack. -++ */ -++ int F_SAME = 3; -++ -++ /** -++ * Represents a compressed frame with exactly the same locals as the -++ * previous frame and with a single value on the stack. -++ */ -++ int F_SAME1 = 4; -++ -++ Integer TOP = new Integer(0); -++ Integer INTEGER = new Integer(1); -++ Integer FLOAT = new Integer(2); -++ Integer DOUBLE = new Integer(3); -++ Integer LONG = new Integer(4); -++ Integer NULL = new Integer(5); -++ Integer UNINITIALIZED_THIS = new Integer(6); -++ -++ // opcodes // visit method (- = idem) -++ -++ int NOP = 0; // visitInsn -++ int ACONST_NULL = 1; // - -++ int ICONST_M1 = 2; // - -++ int ICONST_0 = 3; // - -++ int ICONST_1 = 4; // - -++ int ICONST_2 = 5; // - -++ int ICONST_3 = 6; // - -++ int ICONST_4 = 7; // - -++ int ICONST_5 = 8; // - -++ int LCONST_0 = 9; // - -++ int LCONST_1 = 10; // - -++ int FCONST_0 = 11; // - -++ int FCONST_1 = 12; // - -++ int FCONST_2 = 13; // - -++ int DCONST_0 = 14; // - -++ int DCONST_1 = 15; // - -++ int BIPUSH = 16; // visitIntInsn -++ int SIPUSH = 17; // - -++ int LDC = 18; // visitLdcInsn -++ // int LDC_W = 19; // - -++ // int LDC2_W = 20; // - -++ int ILOAD = 21; // visitVarInsn -++ int LLOAD = 22; // - -++ int FLOAD = 23; // - -++ int DLOAD = 24; // - -++ int ALOAD = 25; // - -++ // int ILOAD_0 = 26; // - -++ // int ILOAD_1 = 27; // - -++ // int ILOAD_2 = 28; // - -++ // int ILOAD_3 = 29; // - -++ // int LLOAD_0 = 30; // - -++ // int LLOAD_1 = 31; // - -++ // int LLOAD_2 = 32; // - -++ // int LLOAD_3 = 33; // - -++ // int FLOAD_0 = 34; // - -++ // int FLOAD_1 = 35; // - -++ // int FLOAD_2 = 36; // - -++ // int FLOAD_3 = 37; // - -++ // int DLOAD_0 = 38; // - -++ // int DLOAD_1 = 39; // - -++ // int DLOAD_2 = 40; // - -++ // int DLOAD_3 = 41; // - -++ // int ALOAD_0 = 42; // - -++ // int ALOAD_1 = 43; // - -++ // int ALOAD_2 = 44; // - -++ // int ALOAD_3 = 45; // - -++ int IALOAD = 46; // visitInsn -++ int LALOAD = 47; // - -++ int FALOAD = 48; // - -++ int DALOAD = 49; // - -++ int AALOAD = 50; // - -++ int BALOAD = 51; // - -++ int CALOAD = 52; // - -++ int SALOAD = 53; // - -++ int ISTORE = 54; // visitVarInsn -++ int LSTORE = 55; // - -++ int FSTORE = 56; // - -++ int DSTORE = 57; // - -++ int ASTORE = 58; // - -++ // int ISTORE_0 = 59; // - -++ // int ISTORE_1 = 60; // - -++ // int ISTORE_2 = 61; // - -++ // int ISTORE_3 = 62; // - -++ // int LSTORE_0 = 63; // - -++ // int LSTORE_1 = 64; // - -++ // int LSTORE_2 = 65; // - -++ // int LSTORE_3 = 66; // - -++ // int FSTORE_0 = 67; // - -++ // int FSTORE_1 = 68; // - -++ // int FSTORE_2 = 69; // - -++ // int FSTORE_3 = 70; // - -++ // int DSTORE_0 = 71; // - -++ // int DSTORE_1 = 72; // - -++ // int DSTORE_2 = 73; // - -++ // int DSTORE_3 = 74; // - -++ // int ASTORE_0 = 75; // - -++ // int ASTORE_1 = 76; // - -++ // int ASTORE_2 = 77; // - -++ // int ASTORE_3 = 78; // - -++ int IASTORE = 79; // visitInsn -++ int LASTORE = 80; // - -++ int FASTORE = 81; // - -++ int DASTORE = 82; // - -++ int AASTORE = 83; // - -++ int BASTORE = 84; // - -++ int CASTORE = 85; // - -++ int SASTORE = 86; // - -++ int POP = 87; // - -++ int POP2 = 88; // - -++ int DUP = 89; // - -++ int DUP_X1 = 90; // - -++ int DUP_X2 = 91; // - -++ int DUP2 = 92; // - -++ int DUP2_X1 = 93; // - -++ int DUP2_X2 = 94; // - -++ int SWAP = 95; // - -++ int IADD = 96; // - -++ int LADD = 97; // - -++ int FADD = 98; // - -++ int DADD = 99; // - -++ int ISUB = 100; // - -++ int LSUB = 101; // - -++ int FSUB = 102; // - -++ int DSUB = 103; // - -++ int IMUL = 104; // - -++ int LMUL = 105; // - -++ int FMUL = 106; // - -++ int DMUL = 107; // - -++ int IDIV = 108; // - -++ int LDIV = 109; // - -++ int FDIV = 110; // - -++ int DDIV = 111; // - -++ int IREM = 112; // - -++ int LREM = 113; // - -++ int FREM = 114; // - -++ int DREM = 115; // - -++ int INEG = 116; // - -++ int LNEG = 117; // - -++ int FNEG = 118; // - -++ int DNEG = 119; // - -++ int ISHL = 120; // - -++ int LSHL = 121; // - -++ int ISHR = 122; // - -++ int LSHR = 123; // - -++ int IUSHR = 124; // - -++ int LUSHR = 125; // - -++ int IAND = 126; // - -++ int LAND = 127; // - -++ int IOR = 128; // - -++ int LOR = 129; // - -++ int IXOR = 130; // - -++ int LXOR = 131; // - -++ int IINC = 132; // visitIincInsn -++ int I2L = 133; // visitInsn -++ int I2F = 134; // - -++ int I2D = 135; // - -++ int L2I = 136; // - -++ int L2F = 137; // - -++ int L2D = 138; // - -++ int F2I = 139; // - -++ int F2L = 140; // - -++ int F2D = 141; // - -++ int D2I = 142; // - -++ int D2L = 143; // - -++ int D2F = 144; // - -++ int I2B = 145; // - -++ int I2C = 146; // - -++ int I2S = 147; // - -++ int LCMP = 148; // - -++ int FCMPL = 149; // - -++ int FCMPG = 150; // - -++ int DCMPL = 151; // - -++ int DCMPG = 152; // - -++ int IFEQ = 153; // visitJumpInsn -++ int IFNE = 154; // - -++ int IFLT = 155; // - -++ int IFGE = 156; // - -++ int IFGT = 157; // - -++ int IFLE = 158; // - -++ int IF_ICMPEQ = 159; // - -++ int IF_ICMPNE = 160; // - -++ int IF_ICMPLT = 161; // - -++ int IF_ICMPGE = 162; // - -++ int IF_ICMPGT = 163; // - -++ int IF_ICMPLE = 164; // - -++ int IF_ACMPEQ = 165; // - -++ int IF_ACMPNE = 166; // - -++ int GOTO = 167; // - -++ int JSR = 168; // - -++ int RET = 169; // visitVarInsn -++ int TABLESWITCH = 170; // visiTableSwitchInsn -++ int LOOKUPSWITCH = 171; // visitLookupSwitch -++ int IRETURN = 172; // visitInsn -++ int LRETURN = 173; // - -++ int FRETURN = 174; // - -++ int DRETURN = 175; // - -++ int ARETURN = 176; // - -++ int RETURN = 177; // - -++ int GETSTATIC = 178; // visitFieldInsn -++ int PUTSTATIC = 179; // - -++ int GETFIELD = 180; // - -++ int PUTFIELD = 181; // - -++ int INVOKEVIRTUAL = 182; // visitMethodInsn -++ int INVOKESPECIAL = 183; // - -++ int INVOKESTATIC = 184; // - -++ int INVOKEINTERFACE = 185; // - -++ int INVOKEDYNAMIC = 186; // visitInvokeDynamicInsn -++ int NEW = 187; // visitTypeInsn -++ int NEWARRAY = 188; // visitIntInsn -++ int ANEWARRAY = 189; // visitTypeInsn -++ int ARRAYLENGTH = 190; // visitInsn -++ int ATHROW = 191; // - -++ int CHECKCAST = 192; // visitTypeInsn -++ int INSTANCEOF = 193; // - -++ int MONITORENTER = 194; // visitInsn -++ int MONITOREXIT = 195; // - -++ // int WIDE = 196; // NOT VISITED -++ int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn -++ int IFNULL = 198; // visitJumpInsn -++ int IFNONNULL = 199; // - -++ // int GOTO_W = 200; // - -++ // int JSR_W = 201; // - -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/Type.java b/contrib/asm/src/org/objectweb/asm/Type.java -+new file mode 100644 -+index 0000000..33a8bf0 -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/Type.java -+@@ -0,0 +1,896 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2011 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++package org.objectweb.asm; -++ -++import java.lang.reflect.Constructor; -++import java.lang.reflect.Method; -++ -++/** -++ * A Java field or method type. This class can be used to make it easier to -++ * manipulate type and method descriptors. -++ * -++ * @author Eric Bruneton -++ * @author Chris Nokleberg -++ */ -++public class Type { -++ -++ /** -++ * The sort of the <tt>void</tt> type. See {@link #getSort getSort}. -++ */ -++ public static final int VOID = 0; -++ -++ /** -++ * The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}. -++ */ -++ public static final int BOOLEAN = 1; -++ -++ /** -++ * The sort of the <tt>char</tt> type. See {@link #getSort getSort}. -++ */ -++ public static final int CHAR = 2; -++ -++ /** -++ * The sort of the <tt>byte</tt> type. See {@link #getSort getSort}. -++ */ -++ public static final int BYTE = 3; -++ -++ /** -++ * The sort of the <tt>short</tt> type. See {@link #getSort getSort}. -++ */ -++ public static final int SHORT = 4; -++ -++ /** -++ * The sort of the <tt>int</tt> type. See {@link #getSort getSort}. -++ */ -++ public static final int INT = 5; -++ -++ /** -++ * The sort of the <tt>float</tt> type. See {@link #getSort getSort}. -++ */ -++ public static final int FLOAT = 6; -++ -++ /** -++ * The sort of the <tt>long</tt> type. See {@link #getSort getSort}. -++ */ -++ public static final int LONG = 7; -++ -++ /** -++ * The sort of the <tt>double</tt> type. See {@link #getSort getSort}. -++ */ -++ public static final int DOUBLE = 8; -++ -++ /** -++ * The sort of array reference types. See {@link #getSort getSort}. -++ */ -++ public static final int ARRAY = 9; -++ -++ /** -++ * The sort of object reference types. See {@link #getSort getSort}. -++ */ -++ public static final int OBJECT = 10; -++ -++ /** -++ * The sort of method types. See {@link #getSort getSort}. -++ */ -++ public static final int METHOD = 11; -++ -++ /** -++ * The <tt>void</tt> type. -++ */ -++ public static final Type VOID_TYPE = new Type(VOID, null, ('V' << 24) -++ | (5 << 16) | (0 << 8) | 0, 1); -++ -++ /** -++ * The <tt>boolean</tt> type. -++ */ -++ public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, null, ('Z' << 24) -++ | (0 << 16) | (5 << 8) | 1, 1); -++ -++ /** -++ * The <tt>char</tt> type. -++ */ -++ public static final Type CHAR_TYPE = new Type(CHAR, null, ('C' << 24) -++ | (0 << 16) | (6 << 8) | 1, 1); -++ -++ /** -++ * The <tt>byte</tt> type. -++ */ -++ public static final Type BYTE_TYPE = new Type(BYTE, null, ('B' << 24) -++ | (0 << 16) | (5 << 8) | 1, 1); -++ -++ /** -++ * The <tt>short</tt> type. -++ */ -++ public static final Type SHORT_TYPE = new Type(SHORT, null, ('S' << 24) -++ | (0 << 16) | (7 << 8) | 1, 1); -++ -++ /** -++ * The <tt>int</tt> type. -++ */ -++ public static final Type INT_TYPE = new Type(INT, null, ('I' << 24) -++ | (0 << 16) | (0 << 8) | 1, 1); -++ -++ /** -++ * The <tt>float</tt> type. -++ */ -++ public static final Type FLOAT_TYPE = new Type(FLOAT, null, ('F' << 24) -++ | (2 << 16) | (2 << 8) | 1, 1); -++ -++ /** -++ * The <tt>long</tt> type. -++ */ -++ public static final Type LONG_TYPE = new Type(LONG, null, ('J' << 24) -++ | (1 << 16) | (1 << 8) | 2, 1); -++ -++ /** -++ * The <tt>double</tt> type. -++ */ -++ public static final Type DOUBLE_TYPE = new Type(DOUBLE, null, ('D' << 24) -++ | (3 << 16) | (3 << 8) | 2, 1); -++ -++ // ------------------------------------------------------------------------ -++ // Fields -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * The sort of this Java type. -++ */ -++ private final int sort; -++ -++ /** -++ * A buffer containing the internal name of this Java type. This field is -++ * only used for reference types. -++ */ -++ private final char[] buf; -++ -++ /** -++ * The offset of the internal name of this Java type in {@link #buf buf} or, -++ * for primitive types, the size, descriptor and getOpcode offsets for this -++ * type (byte 0 contains the size, byte 1 the descriptor, byte 2 the offset -++ * for IALOAD or IASTORE, byte 3 the offset for all other instructions). -++ */ -++ private final int off; -++ -++ /** -++ * The length of the internal name of this Java type. -++ */ -++ private final int len; -++ -++ // ------------------------------------------------------------------------ -++ // Constructors -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Constructs a reference type. -++ * -++ * @param sort -++ * the sort of the reference type to be constructed. -++ * @param buf -++ * a buffer containing the descriptor of the previous type. -++ * @param off -++ * the offset of this descriptor in the previous buffer. -++ * @param len -++ * the length of this descriptor. -++ */ -++ private Type(final int sort, final char[] buf, final int off, final int len) { -++ this.sort = sort; -++ this.buf = buf; -++ this.off = off; -++ this.len = len; -++ } -++ -++ /** -++ * Returns the Java type corresponding to the given type descriptor. -++ * -++ * @param typeDescriptor -++ * a field or method type descriptor. -++ * @return the Java type corresponding to the given type descriptor. -++ */ -++ public static Type getType(final String typeDescriptor) { -++ return getType(typeDescriptor.toCharArray(), 0); -++ } -++ -++ /** -++ * Returns the Java type corresponding to the given internal name. -++ * -++ * @param internalName -++ * an internal name. -++ * @return the Java type corresponding to the given internal name. -++ */ -++ public static Type getObjectType(final String internalName) { -++ char[] buf = internalName.toCharArray(); -++ return new Type(buf[0] == '[' ? ARRAY : OBJECT, buf, 0, buf.length); -++ } -++ -++ /** -++ * Returns the Java type corresponding to the given method descriptor. -++ * Equivalent to <code>Type.getType(methodDescriptor)</code>. -++ * -++ * @param methodDescriptor -++ * a method descriptor. -++ * @return the Java type corresponding to the given method descriptor. -++ */ -++ public static Type getMethodType(final String methodDescriptor) { -++ return getType(methodDescriptor.toCharArray(), 0); -++ } -++ -++ /** -++ * Returns the Java method type corresponding to the given argument and -++ * return types. -++ * -++ * @param returnType -++ * the return type of the method. -++ * @param argumentTypes -++ * the argument types of the method. -++ * @return the Java type corresponding to the given argument and return -++ * types. -++ */ -++ public static Type getMethodType(final Type returnType, -++ final Type... argumentTypes) { -++ return getType(getMethodDescriptor(returnType, argumentTypes)); -++ } -++ -++ /** -++ * Returns the Java type corresponding to the given class. -++ * -++ * @param c -++ * a class. -++ * @return the Java type corresponding to the given class. -++ */ -++ public static Type getType(final Class<?> c) { -++ if (c.isPrimitive()) { -++ if (c == Integer.TYPE) { -++ return INT_TYPE; -++ } else if (c == Void.TYPE) { -++ return VOID_TYPE; -++ } else if (c == Boolean.TYPE) { -++ return BOOLEAN_TYPE; -++ } else if (c == Byte.TYPE) { -++ return BYTE_TYPE; -++ } else if (c == Character.TYPE) { -++ return CHAR_TYPE; -++ } else if (c == Short.TYPE) { -++ return SHORT_TYPE; -++ } else if (c == Double.TYPE) { -++ return DOUBLE_TYPE; -++ } else if (c == Float.TYPE) { -++ return FLOAT_TYPE; -++ } else /* if (c == Long.TYPE) */{ -++ return LONG_TYPE; -++ } -++ } else { -++ return getType(getDescriptor(c)); -++ } -++ } -++ -++ /** -++ * Returns the Java method type corresponding to the given constructor. -++ * -++ * @param c -++ * a {@link Constructor Constructor} object. -++ * @return the Java method type corresponding to the given constructor. -++ */ -++ public static Type getType(final Constructor<?> c) { -++ return getType(getConstructorDescriptor(c)); -++ } -++ -++ /** -++ * Returns the Java method type corresponding to the given method. -++ * -++ * @param m -++ * a {@link Method Method} object. -++ * @return the Java method type corresponding to the given method. -++ */ -++ public static Type getType(final Method m) { -++ return getType(getMethodDescriptor(m)); -++ } -++ -++ /** -++ * Returns the Java types corresponding to the argument types of the given -++ * method descriptor. -++ * -++ * @param methodDescriptor -++ * a method descriptor. -++ * @return the Java types corresponding to the argument types of the given -++ * method descriptor. -++ */ -++ public static Type[] getArgumentTypes(final String methodDescriptor) { -++ char[] buf = methodDescriptor.toCharArray(); -++ int off = 1; -++ int size = 0; -++ while (true) { -++ char car = buf[off++]; -++ if (car == ')') { -++ break; -++ } else if (car == 'L') { -++ while (buf[off++] != ';') { -++ } -++ ++size; -++ } else if (car != '[') { -++ ++size; -++ } -++ } -++ Type[] args = new Type[size]; -++ off = 1; -++ size = 0; -++ while (buf[off] != ')') { -++ args[size] = getType(buf, off); -++ off += args[size].len + (args[size].sort == OBJECT ? 2 : 0); -++ size += 1; -++ } -++ return args; -++ } -++ -++ /** -++ * Returns the Java types corresponding to the argument types of the given -++ * method. -++ * -++ * @param method -++ * a method. -++ * @return the Java types corresponding to the argument types of the given -++ * method. -++ */ -++ public static Type[] getArgumentTypes(final Method method) { -++ Class<?>[] classes = method.getParameterTypes(); -++ Type[] types = new Type[classes.length]; -++ for (int i = classes.length - 1; i >= 0; --i) { -++ types[i] = getType(classes[i]); -++ } -++ return types; -++ } -++ -++ /** -++ * Returns the Java type corresponding to the return type of the given -++ * method descriptor. -++ * -++ * @param methodDescriptor -++ * a method descriptor. -++ * @return the Java type corresponding to the return type of the given -++ * method descriptor. -++ */ -++ public static Type getReturnType(final String methodDescriptor) { -++ char[] buf = methodDescriptor.toCharArray(); -++ return getType(buf, methodDescriptor.indexOf(')') + 1); -++ } -++ -++ /** -++ * Returns the Java type corresponding to the return type of the given -++ * method. -++ * -++ * @param method -++ * a method. -++ * @return the Java type corresponding to the return type of the given -++ * method. -++ */ -++ public static Type getReturnType(final Method method) { -++ return getType(method.getReturnType()); -++ } -++ -++ /** -++ * Computes the size of the arguments and of the return value of a method. -++ * -++ * @param desc -++ * the descriptor of a method. -++ * @return the size of the arguments of the method (plus one for the -++ * implicit this argument), argSize, and the size of its return -++ * value, retSize, packed into a single int i = -++ * <tt>(argSize << 2) | retSize</tt> (argSize is therefore equal to -++ * <tt>i >> 2</tt>, and retSize to <tt>i & 0x03</tt>). -++ */ -++ public static int getArgumentsAndReturnSizes(final String desc) { -++ int n = 1; -++ int c = 1; -++ while (true) { -++ char car = desc.charAt(c++); -++ if (car == ')') { -++ car = desc.charAt(c); -++ return n << 2 -++ | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1)); -++ } else if (car == 'L') { -++ while (desc.charAt(c++) != ';') { -++ } -++ n += 1; -++ } else if (car == '[') { -++ while ((car = desc.charAt(c)) == '[') { -++ ++c; -++ } -++ if (car == 'D' || car == 'J') { -++ n -= 1; -++ } -++ } else if (car == 'D' || car == 'J') { -++ n += 2; -++ } else { -++ n += 1; -++ } -++ } -++ } -++ -++ /** -++ * Returns the Java type corresponding to the given type descriptor. For -++ * method descriptors, buf is supposed to contain nothing more than the -++ * descriptor itself. -++ * -++ * @param buf -++ * a buffer containing a type descriptor. -++ * @param off -++ * the offset of this descriptor in the previous buffer. -++ * @return the Java type corresponding to the given type descriptor. -++ */ -++ private static Type getType(final char[] buf, final int off) { -++ int len; -++ switch (buf[off]) { -++ case 'V': -++ return VOID_TYPE; -++ case 'Z': -++ return BOOLEAN_TYPE; -++ case 'C': -++ return CHAR_TYPE; -++ case 'B': -++ return BYTE_TYPE; -++ case 'S': -++ return SHORT_TYPE; -++ case 'I': -++ return INT_TYPE; -++ case 'F': -++ return FLOAT_TYPE; -++ case 'J': -++ return LONG_TYPE; -++ case 'D': -++ return DOUBLE_TYPE; -++ case '[': -++ len = 1; -++ while (buf[off + len] == '[') { -++ ++len; -++ } -++ if (buf[off + len] == 'L') { -++ ++len; -++ while (buf[off + len] != ';') { -++ ++len; -++ } -++ } -++ return new Type(ARRAY, buf, off, len + 1); -++ case 'L': -++ len = 1; -++ while (buf[off + len] != ';') { -++ ++len; -++ } -++ return new Type(OBJECT, buf, off + 1, len - 1); -++ // case '(': -++ default: -++ return new Type(METHOD, buf, off, buf.length - off); -++ } -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Accessors -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Returns the sort of this Java type. -++ * -++ * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN}, {@link #CHAR CHAR}, -++ * {@link #BYTE BYTE}, {@link #SHORT SHORT}, {@link #INT INT}, -++ * {@link #FLOAT FLOAT}, {@link #LONG LONG}, {@link #DOUBLE DOUBLE}, -++ * {@link #ARRAY ARRAY}, {@link #OBJECT OBJECT} or {@link #METHOD -++ * METHOD}. -++ */ -++ public int getSort() { -++ return sort; -++ } -++ -++ /** -++ * Returns the number of dimensions of this array type. This method should -++ * only be used for an array type. -++ * -++ * @return the number of dimensions of this array type. -++ */ -++ public int getDimensions() { -++ int i = 1; -++ while (buf[off + i] == '[') { -++ ++i; -++ } -++ return i; -++ } -++ -++ /** -++ * Returns the type of the elements of this array type. This method should -++ * only be used for an array type. -++ * -++ * @return Returns the type of the elements of this array type. -++ */ -++ public Type getElementType() { -++ return getType(buf, off + getDimensions()); -++ } -++ -++ /** -++ * Returns the binary name of the class corresponding to this type. This -++ * method must not be used on method types. -++ * -++ * @return the binary name of the class corresponding to this type. -++ */ -++ public String getClassName() { -++ switch (sort) { -++ case VOID: -++ return "void"; -++ case BOOLEAN: -++ return "boolean"; -++ case CHAR: -++ return "char"; -++ case BYTE: -++ return "byte"; -++ case SHORT: -++ return "short"; -++ case INT: -++ return "int"; -++ case FLOAT: -++ return "float"; -++ case LONG: -++ return "long"; -++ case DOUBLE: -++ return "double"; -++ case ARRAY: -++ StringBuilder sb = new StringBuilder(getElementType().getClassName()); -++ for (int i = getDimensions(); i > 0; --i) { -++ sb.append("[]"); -++ } -++ return sb.toString(); -++ case OBJECT: -++ return new String(buf, off, len).replace('/', '.'); -++ default: -++ return null; -++ } -++ } -++ -++ /** -++ * Returns the internal name of the class corresponding to this object or -++ * array type. The internal name of a class is its fully qualified name (as -++ * returned by Class.getName(), where '.' are replaced by '/'. This method -++ * should only be used for an object or array type. -++ * -++ * @return the internal name of the class corresponding to this object type. -++ */ -++ public String getInternalName() { -++ return new String(buf, off, len); -++ } -++ -++ /** -++ * Returns the argument types of methods of this type. This method should -++ * only be used for method types. -++ * -++ * @return the argument types of methods of this type. -++ */ -++ public Type[] getArgumentTypes() { -++ return getArgumentTypes(getDescriptor()); -++ } -++ -++ /** -++ * Returns the return type of methods of this type. This method should only -++ * be used for method types. -++ * -++ * @return the return type of methods of this type. -++ */ -++ public Type getReturnType() { -++ return getReturnType(getDescriptor()); -++ } -++ -++ /** -++ * Returns the size of the arguments and of the return value of methods of -++ * this type. This method should only be used for method types. -++ * -++ * @return the size of the arguments (plus one for the implicit this -++ * argument), argSize, and the size of the return value, retSize, -++ * packed into a single -++ * int i = <tt>(argSize << 2) | retSize</tt> -++ * (argSize is therefore equal to <tt>i >> 2</tt>, -++ * and retSize to <tt>i & 0x03</tt>). -++ */ -++ public int getArgumentsAndReturnSizes() { -++ return getArgumentsAndReturnSizes(getDescriptor()); -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Conversion to type descriptors -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Returns the descriptor corresponding to this Java type. -++ * -++ * @return the descriptor corresponding to this Java type. -++ */ -++ public String getDescriptor() { -++ StringBuffer buf = new StringBuffer(); -++ getDescriptor(buf); -++ return buf.toString(); -++ } -++ -++ /** -++ * Returns the descriptor corresponding to the given argument and return -++ * types. -++ * -++ * @param returnType -++ * the return type of the method. -++ * @param argumentTypes -++ * the argument types of the method. -++ * @return the descriptor corresponding to the given argument and return -++ * types. -++ */ -++ public static String getMethodDescriptor(final Type returnType, -++ final Type... argumentTypes) { -++ StringBuffer buf = new StringBuffer(); -++ buf.append('('); -++ for (int i = 0; i < argumentTypes.length; ++i) { -++ argumentTypes[i].getDescriptor(buf); -++ } -++ buf.append(')'); -++ returnType.getDescriptor(buf); -++ return buf.toString(); -++ } -++ -++ /** -++ * Appends the descriptor corresponding to this Java type to the given -++ * string buffer. -++ * -++ * @param buf -++ * the string buffer to which the descriptor must be appended. -++ */ -++ private void getDescriptor(final StringBuffer buf) { -++ if (this.buf == null) { -++ // descriptor is in byte 3 of 'off' for primitive types (buf == -++ // null) -++ buf.append((char) ((off & 0xFF000000) >>> 24)); -++ } else if (sort == OBJECT) { -++ buf.append('L'); -++ buf.append(this.buf, off, len); -++ buf.append(';'); -++ } else { // sort == ARRAY || sort == METHOD -++ buf.append(this.buf, off, len); -++ } -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Direct conversion from classes to type descriptors, -++ // without intermediate Type objects -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Returns the internal name of the given class. The internal name of a -++ * class is its fully qualified name, as returned by Class.getName(), where -++ * '.' are replaced by '/'. -++ * -++ * @param c -++ * an object or array class. -++ * @return the internal name of the given class. -++ */ -++ public static String getInternalName(final Class<?> c) { -++ return c.getName().replace('.', '/'); -++ } -++ -++ /** -++ * Returns the descriptor corresponding to the given Java type. -++ * -++ * @param c -++ * an object class, a primitive class or an array class. -++ * @return the descriptor corresponding to the given class. -++ */ -++ public static String getDescriptor(final Class<?> c) { -++ StringBuffer buf = new StringBuffer(); -++ getDescriptor(buf, c); -++ return buf.toString(); -++ } -++ -++ /** -++ * Returns the descriptor corresponding to the given constructor. -++ * -++ * @param c -++ * a {@link Constructor Constructor} object. -++ * @return the descriptor of the given constructor. -++ */ -++ public static String getConstructorDescriptor(final Constructor<?> c) { -++ Class<?>[] parameters = c.getParameterTypes(); -++ StringBuffer buf = new StringBuffer(); -++ buf.append('('); -++ for (int i = 0; i < parameters.length; ++i) { -++ getDescriptor(buf, parameters[i]); -++ } -++ return buf.append(")V").toString(); -++ } -++ -++ /** -++ * Returns the descriptor corresponding to the given method. -++ * -++ * @param m -++ * a {@link Method Method} object. -++ * @return the descriptor of the given method. -++ */ -++ public static String getMethodDescriptor(final Method m) { -++ Class<?>[] parameters = m.getParameterTypes(); -++ StringBuffer buf = new StringBuffer(); -++ buf.append('('); -++ for (int i = 0; i < parameters.length; ++i) { -++ getDescriptor(buf, parameters[i]); -++ } -++ buf.append(')'); -++ getDescriptor(buf, m.getReturnType()); -++ return buf.toString(); -++ } -++ -++ /** -++ * Appends the descriptor of the given class to the given string buffer. -++ * -++ * @param buf -++ * the string buffer to which the descriptor must be appended. -++ * @param c -++ * the class whose descriptor must be computed. -++ */ -++ private static void getDescriptor(final StringBuffer buf, final Class<?> c) { -++ Class<?> d = c; -++ while (true) { -++ if (d.isPrimitive()) { -++ char car; -++ if (d == Integer.TYPE) { -++ car = 'I'; -++ } else if (d == Void.TYPE) { -++ car = 'V'; -++ } else if (d == Boolean.TYPE) { -++ car = 'Z'; -++ } else if (d == Byte.TYPE) { -++ car = 'B'; -++ } else if (d == Character.TYPE) { -++ car = 'C'; -++ } else if (d == Short.TYPE) { -++ car = 'S'; -++ } else if (d == Double.TYPE) { -++ car = 'D'; -++ } else if (d == Float.TYPE) { -++ car = 'F'; -++ } else /* if (d == Long.TYPE) */{ -++ car = 'J'; -++ } -++ buf.append(car); -++ return; -++ } else if (d.isArray()) { -++ buf.append('['); -++ d = d.getComponentType(); -++ } else { -++ buf.append('L'); -++ String name = d.getName(); -++ int len = name.length(); -++ for (int i = 0; i < len; ++i) { -++ char car = name.charAt(i); -++ buf.append(car == '.' ? '/' : car); -++ } -++ buf.append(';'); -++ return; -++ } -++ } -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Corresponding size and opcodes -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Returns the size of values of this type. This method must not be used for -++ * method types. -++ * -++ * @return the size of values of this type, i.e., 2 for <tt>long</tt> and -++ * <tt>double</tt>, 0 for <tt>void</tt> and 1 otherwise. -++ */ -++ public int getSize() { -++ // the size is in byte 0 of 'off' for primitive types (buf == null) -++ return buf == null ? (off & 0xFF) : 1; -++ } -++ -++ /** -++ * Returns a JVM instruction opcode adapted to this Java type. This method -++ * must not be used for method types. -++ * -++ * @param opcode -++ * a JVM instruction opcode. This opcode must be one of ILOAD, -++ * ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, -++ * ISHL, ISHR, IUSHR, IAND, IOR, IXOR and IRETURN. -++ * @return an opcode that is similar to the given opcode, but adapted to -++ * this Java type. For example, if this type is <tt>float</tt> and -++ * <tt>opcode</tt> is IRETURN, this method returns FRETURN. -++ */ -++ public int getOpcode(final int opcode) { -++ if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) { -++ // the offset for IALOAD or IASTORE is in byte 1 of 'off' for -++ // primitive types (buf == null) -++ return opcode + (buf == null ? (off & 0xFF00) >> 8 : 4); -++ } else { -++ // the offset for other instructions is in byte 2 of 'off' for -++ // primitive types (buf == null) -++ return opcode + (buf == null ? (off & 0xFF0000) >> 16 : 4); -++ } -++ } -++ -++ // ------------------------------------------------------------------------ -++ // Equals, hashCode and toString -++ // ------------------------------------------------------------------------ -++ -++ /** -++ * Tests if the given object is equal to this type. -++ * -++ * @param o -++ * the object to be compared to this type. -++ * @return <tt>true</tt> if the given object is equal to this type. -++ */ -++ @Override -++ public boolean equals(final Object o) { -++ if (this == o) { -++ return true; -++ } -++ if (!(o instanceof Type)) { -++ return false; -++ } -++ Type t = (Type) o; -++ if (sort != t.sort) { -++ return false; -++ } -++ if (sort >= ARRAY) { -++ if (len != t.len) { -++ return false; -++ } -++ for (int i = off, j = t.off, end = i + len; i < end; i++, j++) { -++ if (buf[i] != t.buf[j]) { -++ return false; -++ } -++ } -++ } -++ return true; -++ } -++ -++ /** -++ * Returns a hash code value for this type. -++ * -++ * @return a hash code value for this type. -++ */ -++ @Override -++ public int hashCode() { -++ int hc = 13 * sort; -++ if (sort >= ARRAY) { -++ for (int i = off, end = i + len; i < end; i++) { -++ hc = 17 * (hc + buf[i]); -++ } -++ } -++ return hc; -++ } -++ -++ /** -++ * Returns a string representation of this type. -++ * -++ * @return the descriptor of this type. -++ */ -++ @Override -++ public String toString() { -++ return getDescriptor(); -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/TypePath.java b/contrib/asm/src/org/objectweb/asm/TypePath.java -+new file mode 100644 -+index 0000000..d9c99b1 -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/TypePath.java -+@@ -0,0 +1,196 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2013 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++ -++package org.objectweb.asm; -++ -++/** -++ * The path to a type argument, wildcard bound, array element type, or static -++ * inner type within an enclosing type. -++ * -++ * @author Eric Bruneton -++ */ -++public class TypePath { -++ -++ /** -++ * A type path step that steps into the element type of an array type. See -++ * {@link #getStep getStep}. -++ */ -++ public final static int ARRAY_ELEMENT = 0; -++ -++ /** -++ * A type path step that steps into the nested type of a class type. See -++ * {@link #getStep getStep}. -++ */ -++ public final static int INNER_TYPE = 1; -++ -++ /** -++ * A type path step that steps into the bound of a wildcard type. See -++ * {@link #getStep getStep}. -++ */ -++ public final static int WILDCARD_BOUND = 2; -++ -++ /** -++ * A type path step that steps into a type argument of a generic type. See -++ * {@link #getStep getStep}. -++ */ -++ public final static int TYPE_ARGUMENT = 3; -++ -++ /** -++ * The byte array where the path is stored, in Java class file format. -++ */ -++ byte[] b; -++ -++ /** -++ * The offset of the first byte of the type path in 'b'. -++ */ -++ int offset; -++ -++ /** -++ * Creates a new type path. -++ * -++ * @param b -++ * the byte array containing the type path in Java class file -++ * format. -++ * @param offset -++ * the offset of the first byte of the type path in 'b'. -++ */ -++ TypePath(byte[] b, int offset) { -++ this.b = b; -++ this.offset = offset; -++ } -++ -++ /** -++ * Returns the length of this path. -++ * -++ * @return the length of this path. -++ */ -++ public int getLength() { -++ return b[offset]; -++ } -++ -++ /** -++ * Returns the value of the given step of this path. -++ * -++ * @param index -++ * an index between 0 and {@link #getLength()}, exclusive. -++ * @return {@link #ARRAY_ELEMENT ARRAY_ELEMENT}, {@link #INNER_TYPE -++ * INNER_TYPE}, {@link #WILDCARD_BOUND WILDCARD_BOUND}, or -++ * {@link #TYPE_ARGUMENT TYPE_ARGUMENT}. -++ */ -++ public int getStep(int index) { -++ return b[offset + 2 * index + 1]; -++ } -++ -++ /** -++ * Returns the index of the type argument that the given step is stepping -++ * into. This method should only be used for steps whose value is -++ * {@link #TYPE_ARGUMENT TYPE_ARGUMENT}. -++ * -++ * @param index -++ * an index between 0 and {@link #getLength()}, exclusive. -++ * @return the index of the type argument that the given step is stepping -++ * into. -++ */ -++ public int getStepArgument(int index) { -++ return b[offset + 2 * index + 2]; -++ } -++ -++ /** -++ * Converts a type path in string form, in the format used by -++ * {@link #toString()}, into a TypePath object. -++ * -++ * @param typePath -++ * a type path in string form, in the format used by -++ * {@link #toString()}. May be null or empty. -++ * @return the corresponding TypePath object, or null if the path is empty. -++ */ -++ public static TypePath fromString(final String typePath) { -++ if (typePath == null || typePath.length() == 0) { -++ return null; -++ } -++ int n = typePath.length(); -++ ByteVector out = new ByteVector(n); -++ out.putByte(0); -++ for (int i = 0; i < n;) { -++ char c = typePath.charAt(i++); -++ if (c == '[') { -++ out.put11(ARRAY_ELEMENT, 0); -++ } else if (c == '.') { -++ out.put11(INNER_TYPE, 0); -++ } else if (c == '*') { -++ out.put11(WILDCARD_BOUND, 0); -++ } else if (c >= '0' && c <= '9') { -++ int typeArg = c - '0'; -++ while (i < n && (c = typePath.charAt(i)) >= '0' && c <= '9') { -++ typeArg = typeArg * 10 + c - '0'; -++ i += 1; -++ } -++ if (i < n && typePath.charAt(i) == ';') { -++ i += 1; -++ } -++ out.put11(TYPE_ARGUMENT, typeArg); -++ } -++ } -++ out.data[0] = (byte) (out.length / 2); -++ return new TypePath(out.data, 0); -++ } -++ -++ /** -++ * Returns a string representation of this type path. {@link #ARRAY_ELEMENT -++ * ARRAY_ELEMENT} steps are represented with '[', {@link #INNER_TYPE -++ * INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND WILDCARD_BOUND} steps -++ * with '*' and {@link #TYPE_ARGUMENT TYPE_ARGUMENT} steps with their type -++ * argument index in decimal form followed by ';'. -++ */ -++ @Override -++ public String toString() { -++ int length = getLength(); -++ StringBuilder result = new StringBuilder(length * 2); -++ for (int i = 0; i < length; ++i) { -++ switch (getStep(i)) { -++ case ARRAY_ELEMENT: -++ result.append('['); -++ break; -++ case INNER_TYPE: -++ result.append('.'); -++ break; -++ case WILDCARD_BOUND: -++ result.append('*'); -++ break; -++ case TYPE_ARGUMENT: -++ result.append(getStepArgument(i)).append(';'); -++ break; -++ default: -++ result.append('_'); -++ } -++ } -++ return result.toString(); -++ } -++} -+diff --git a/contrib/asm/src/org/objectweb/asm/TypeReference.java b/contrib/asm/src/org/objectweb/asm/TypeReference.java -+new file mode 100644 -+index 0000000..dff76c0 -+--- /dev/null -++++ b/contrib/asm/src/org/objectweb/asm/TypeReference.java -+@@ -0,0 +1,452 @@ -++/*** -++ * ASM: a very small and fast Java bytecode manipulation framework -++ * Copyright (c) 2000-2013 INRIA, France Telecom -++ * All rights reserved. -++ * -++ * Redistribution and use in source and binary forms, with or without -++ * modification, are permitted provided that the following conditions -++ * are met: -++ * 1. Redistributions of source code must retain the above copyright -++ * notice, this list of conditions and the following disclaimer. -++ * 2. Redistributions in binary form must reproduce the above copyright -++ * notice, this list of conditions and the following disclaimer in the -++ * documentation and/or other materials provided with the distribution. -++ * 3. Neither the name of the copyright holders nor the names of its -++ * contributors may be used to endorse or promote products derived from -++ * this software without specific prior written permission. -++ * -++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -++ * THE POSSIBILITY OF SUCH DAMAGE. -++ */ -++ -++package org.objectweb.asm; -++ -++/** -++ * A reference to a type appearing in a class, field or method declaration, or -++ * on an instruction. Such a reference designates the part of the class where -++ * the referenced type is appearing (e.g. an 'extends', 'implements' or 'throws' -++ * clause, a 'new' instruction, a 'catch' clause, a type cast, a local variable -++ * declaration, etc). -++ * -++ * @author Eric Bruneton -++ */ -++public class TypeReference { -++ -++ /** -++ * The sort of type references that target a type parameter of a generic -++ * class. See {@link #getSort getSort}. -++ */ -++ public final static int CLASS_TYPE_PARAMETER = 0x00; -++ -++ /** -++ * The sort of type references that target a type parameter of a generic -++ * method. See {@link #getSort getSort}. -++ */ -++ public final static int METHOD_TYPE_PARAMETER = 0x01; -++ -++ /** -++ * The sort of type references that target the super class of a class or one -++ * of the interfaces it implements. See {@link #getSort getSort}. -++ */ -++ public final static int CLASS_EXTENDS = 0x10; -++ -++ /** -++ * The sort of type references that target a bound of a type parameter of a -++ * generic class. See {@link #getSort getSort}. -++ */ -++ public final static int CLASS_TYPE_PARAMETER_BOUND = 0x11; -++ -++ /** -++ * The sort of type references that target a bound of a type parameter of a -++ * generic method. See {@link #getSort getSort}. -++ */ -++ public final static int METHOD_TYPE_PARAMETER_BOUND = 0x12; -++ -++ /** -++ * The sort of type references that target the type of a field. See -++ * {@link #getSort getSort}. -++ */ -++ public final static int FIELD = 0x13; -++ -++ /** -++ * The sort of type references that target the return type of a method. See -++ * {@link #getSort getSort}. -++ */ -++ public final static int METHOD_RETURN = 0x14; -++ -++ /** -++ * The sort of type references that target the receiver type of a method. -++ * See {@link #getSort getSort}. -++ */ -++ public final static int METHOD_RECEIVER = 0x15; -++ -++ /** -++ * The sort of type references that target the type of a formal parameter of -++ * a method. See {@link #getSort getSort}. -++ */ -++ public final static int METHOD_FORMAL_PARAMETER = 0x16; -++ -++ /** -++ * The sort of type references that target the type of an exception declared -++ * in the throws clause of a method. See {@link #getSort getSort}. -++ */ -++ public final static int THROWS = 0x17; -++ -++ /** -++ * The sort of type references that target the type of a local variable in a -++ * method. See {@link #getSort getSort}. -++ */ -++ public final static int LOCAL_VARIABLE = 0x40; -++ -++ /** -++ * The sort of type references that target the type of a resource variable -++ * in a method. See {@link #getSort getSort}. -++ */ -++ public final static int RESOURCE_VARIABLE = 0x41; -++ -++ /** -++ * The sort of type references that target the type of the exception of a -++ * 'catch' clause in a method. See {@link #getSort getSort}. -++ */ -++ public final static int EXCEPTION_PARAMETER = 0x42; -++ -++ /** -++ * The sort of type references that target the type declared in an -++ * 'instanceof' instruction. See {@link #getSort getSort}. -++ */ -++ public final static int INSTANCEOF = 0x43; -++ -++ /** -++ * The sort of type references that target the type of the object created by -++ * a 'new' instruction. See {@link #getSort getSort}. -++ */ -++ public final static int NEW = 0x44; -++ -++ /** -++ * The sort of type references that target the receiver type of a -++ * constructor reference. See {@link #getSort getSort}. -++ */ -++ public final static int CONSTRUCTOR_REFERENCE = 0x45; -++ -++ /** -++ * The sort of type references that target the receiver type of a method -++ * reference. See {@link #getSort getSort}. -++ */ -++ public final static int METHOD_REFERENCE = 0x46; -++ -++ /** -++ * The sort of type references that target the type declared in an explicit -++ * or implicit cast instruction. See {@link #getSort getSort}. -++ */ -++ public final static int CAST = 0x47; -++ -++ /** -++ * The sort of type references that target a type parameter of a generic -++ * constructor in a constructor call. See {@link #getSort getSort}. -++ */ -++ public final static int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48; -++ -++ /** -++ * The sort of type references that target a type parameter of a generic -++ * method in a method call. See {@link #getSort getSort}. -++ */ -++ public final static int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49; -++ -++ /** -++ * The sort of type references that target a type parameter of a generic -++ * constructor in a constructor reference. See {@link #getSort getSort}. -++ */ -++ public final static int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A; -++ -++ /** -++ * The sort of type references that target a type parameter of a generic -++ * method in a method reference. See {@link #getSort getSort}. -++ */ -++ public final static int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B; -++ -++ /** -++ * The type reference value in Java class file format. -++ */ -++ private int value; -++ -++ /** -++ * Creates a new TypeReference. -++ * -++ * @param typeRef -++ * the int encoded value of the type reference, as received in a -++ * visit method related to type annotations, like -++ * visitTypeAnnotation. -++ */ -++ public TypeReference(int typeRef) { -++ this.value = typeRef; -++ } -++ -++ /** -++ * Returns a type reference of the given sort. -++ * -++ * @param sort -++ * {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN}, -++ * {@link #METHOD_RECEIVER METHOD_RECEIVER}, -++ * {@link #LOCAL_VARIABLE LOCAL_VARIABLE}, -++ * {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE}, -++ * {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW}, -++ * {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, or -++ * {@link #METHOD_REFERENCE METHOD_REFERENCE}. -++ * @return a type reference of the given sort. -++ */ -++ public static TypeReference newTypeReference(int sort) { -++ return new TypeReference(sort << 24); -++ } -++ -++ /** -++ * Returns a reference to a type parameter of a generic class or method. -++ * -++ * @param sort -++ * {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or -++ * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}. -++ * @param paramIndex -++ * the type parameter index. -++ * @return a reference to the given generic class or method type parameter. -++ */ -++ public static TypeReference newTypeParameterReference(int sort, -++ int paramIndex) { -++ return new TypeReference((sort << 24) | (paramIndex << 16)); -++ } -++ -++ /** -++ * Returns a reference to a type parameter bound of a generic class or -++ * method. -++ * -++ * @param sort -++ * {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or -++ * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}. -++ * @param paramIndex -++ * the type parameter index. -++ * @param boundIndex -++ * the type bound index within the above type parameters. -++ * @return a reference to the given generic class or method type parameter -++ * bound. -++ */ -++ public static TypeReference newTypeParameterBoundReference(int sort, -++ int paramIndex, int boundIndex) { -++ return new TypeReference((sort << 24) | (paramIndex << 16) -++ | (boundIndex << 8)); -++ } -++ -++ /** -++ * Returns a reference to the super class or to an interface of the -++ * 'implements' clause of a class. -++ * -++ * @param itfIndex -++ * the index of an interface in the 'implements' clause of a -++ * class, or -1 to reference the super class of the class. -++ * @return a reference to the given super type of a class. -++ */ -++ public static TypeReference newSuperTypeReference(int itfIndex) { -++ itfIndex &= 0xFFFF; -++ return new TypeReference((CLASS_EXTENDS << 24) | (itfIndex << 8)); -++ } -++ -++ /** -++ * Returns a reference to the type of a formal parameter of a method. -++ * -++ * @param paramIndex -++ * the formal parameter index. -++ * -++ * @return a reference to the type of the given method formal parameter. -++ */ -++ public static TypeReference newFormalParameterReference(int paramIndex) { -++ return new TypeReference((METHOD_FORMAL_PARAMETER << 24) -++ | (paramIndex << 16)); -++ } -++ -++ /** -++ * Returns a reference to the type of an exception, in a 'throws' clause of -++ * a method. -++ * -++ * @param exceptionIndex -++ * the index of an exception in a 'throws' clause of a method. -++ * -++ * @return a reference to the type of the given exception. -++ */ -++ public static TypeReference newExceptionReference(int exceptionIndex) { -++ return new TypeReference((THROWS << 24) | (exceptionIndex << 8)); -++ } -++ -++ /** -++ * Returns a reference to the type of the exception declared in a 'catch' -++ * clause of a method. -++ * -++ * @param tryCatchBlockIndex -++ * the index of a try catch block (using the order in which they -++ * are visited with visitTryCatchBlock). -++ * -++ * @return a reference to the type of the given exception. -++ */ -++ public static TypeReference newTryCatchReference(int tryCatchBlockIndex) { -++ return new TypeReference((EXCEPTION_PARAMETER << 24) -++ | (tryCatchBlockIndex << 8)); -++ } -++ -++ /** -++ * Returns a reference to the type of a type argument in a constructor or -++ * method call or reference. -++ * -++ * @param sort -++ * {@link #CAST CAST}, -++ * {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT -++ * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, -++ * {@link #METHOD_INVOCATION_TYPE_ARGUMENT -++ * METHOD_INVOCATION_TYPE_ARGUMENT}, -++ * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT -++ * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or -++ * {@link #METHOD_REFERENCE_TYPE_ARGUMENT -++ * METHOD_REFERENCE_TYPE_ARGUMENT}. -++ * @param argIndex -++ * the type argument index. -++ * -++ * @return a reference to the type of the given type argument. -++ */ -++ public static TypeReference newTypeArgumentReference(int sort, int argIndex) { -++ return new TypeReference((sort << 24) | argIndex); -++ } -++ -++ /** -++ * Returns the sort of this type reference. -++ * -++ * @return {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, -++ * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}, -++ * {@link #CLASS_EXTENDS CLASS_EXTENDS}, -++ * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND}, -++ * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}, -++ * {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN}, -++ * {@link #METHOD_RECEIVER METHOD_RECEIVER}, -++ * {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}, -++ * {@link #THROWS THROWS}, {@link #LOCAL_VARIABLE LOCAL_VARIABLE}, -++ * {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE}, -++ * {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER}, -++ * {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW}, -++ * {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, -++ * {@link #METHOD_REFERENCE METHOD_REFERENCE}, {@link #CAST CAST}, -++ * {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT -++ * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, -++ * {@link #METHOD_INVOCATION_TYPE_ARGUMENT -++ * METHOD_INVOCATION_TYPE_ARGUMENT}, -++ * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT -++ * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or -++ * {@link #METHOD_REFERENCE_TYPE_ARGUMENT -++ * METHOD_REFERENCE_TYPE_ARGUMENT}. -++ */ -++ public int getSort() { -++ return value >>> 24; -++ } -++ -++ /** -++ * Returns the index of the type parameter referenced by this type -++ * reference. This method must only be used for type references whose sort -++ * is {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, -++ * {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}, -++ * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or -++ * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}. -++ * -++ * @return a type parameter index. -++ */ -++ public int getTypeParameterIndex() { -++ return (value & 0x00FF0000) >> 16; -++ } -++ -++ /** -++ * Returns the index of the type parameter bound, within the type parameter -++ * {@link #getTypeParameterIndex}, referenced by this type reference. This -++ * method must only be used for type references whose sort is -++ * {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or -++ * {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}. -++ * -++ * @return a type parameter bound index. -++ */ -++ public int getTypeParameterBoundIndex() { -++ return (value & 0x0000FF00) >> 8; -++ } -++ -++ /** -++ * Returns the index of the "super type" of a class that is referenced by -++ * this type reference. This method must only be used for type references -++ * whose sort is {@link #CLASS_EXTENDS CLASS_EXTENDS}. -++ * -++ * @return the index of an interface in the 'implements' clause of a class, -++ * or -1 if this type reference references the type of the super -++ * class. -++ */ -++ public int getSuperTypeIndex() { -++ return (short) ((value & 0x00FFFF00) >> 8); -++ } -++ -++ /** -++ * Returns the index of the formal parameter whose type is referenced by -++ * this type reference. This method must only be used for type references -++ * whose sort is {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}. -++ * -++ * @return a formal parameter index. -++ */ -++ public int getFormalParameterIndex() { -++ return (value & 0x00FF0000) >> 16; -++ } -++ -++ /** -++ * Returns the index of the exception, in a 'throws' clause of a method, -++ * whose type is referenced by this type reference. This method must only be -++ * used for type references whose sort is {@link #THROWS THROWS}. -++ * -++ * @return the index of an exception in the 'throws' clause of a method. -++ */ -++ public int getExceptionIndex() { -++ return (value & 0x00FFFF00) >> 8; -++ } -++ -++ /** -++ * Returns the index of the try catch block (using the order in which they -++ * are visited with visitTryCatchBlock), whose 'catch' type is referenced by -++ * this type reference. This method must only be used for type references -++ * whose sort is {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER} . -++ * -++ * @return the index of an exception in the 'throws' clause of a method. -++ */ -++ public int getTryCatchBlockIndex() { -++ return (value & 0x00FFFF00) >> 8; -++ } -++ -++ /** -++ * Returns the index of the type argument referenced by this type reference. -++ * This method must only be used for type references whose sort is -++ * {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT -++ * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, -++ * {@link #METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT}, -++ * {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT -++ * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or -++ * {@link #METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}. -++ * -++ * @return a type parameter index. -++ */ -++ public int getTypeArgumentIndex() { -++ return value & 0xFF; -++ } -++ -++ /** -++ * Returns the int encoded value of this type reference, suitable for use in -++ * visit methods related to type annotations, like visitTypeAnnotation. -++ * -++ * @return the int encoded value of this type reference. -++ */ -++ public int getValue() { -++ return value; -++ } -++} +diff --git a/includes/inttypes.h b/includes/inttypes.h +new file mode 100644 +index 0000000..ead903f @@ -70463,4081 +50816,6 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 ++ </ItemGroup> ++</Project> +\ No newline at end of file -+diff --git a/src/devtools/bdj_test.c b/src/devtools/bdj_test.c -+new file mode 100644 -+index 0000000..d9ebd16 -+--- /dev/null -++++ b/src/devtools/bdj_test.c -+@@ -0,0 +1,67 @@ -++/* -++ * This file is part of libbluray -++ * Copyright (C) 2010 William Hahne -++ * -++ * This program is free software; you can redistribute it and/or -++ * modify it under the terms of the GNU General Public License -++ * as published by the Free Software Foundation; either version 2 -++ * of the License, or (at your option) any later version. -++ * -++ * This program is distributed in the hope that it will be useful, -++ * but WITHOUT ANY WARRANTY; without even the implied warranty of -++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -++ * GNU General Public License for more details. -++ * -++ * You should have received a copy of the GNU General Public License -++ * along with this program. If not, see <http://www.gnu.org/licenses/>. -++ * -++ * In addition, as a special exception, the copyright holders of libbluray -++ * gives permission to link the code of its release of libbluray with the -++ * OpenSSL project's "OpenSSL" library (or with modified versions of it -++ * that use the same license as the "OpenSSL" library), and distribute -++ * the linked executables. You must obey the GNU General Public License -++ * in all respects for all of the code used other than "OpenSSL". If you -++ * modify this file, you may extend this exception to your version of the -++ * file, but you are not obligated to do so. If you do not wish to do -++ * so, delete this exception statement from your version. -++ */ -++ -++#include <stdio.h> -++#include <stdlib.h> -++#include <unistd.h> -++ -++#include "libbluray/bluray.h" -++ -++#if defined(_WIN32) -++#include <windows.h> -++#define sleep(x) Sleep(x) -++#endif -++ -++static void _usage(void) { -++ printf("Usage: [path to disc] [starting object]\n"); -++} -++ -++int main(int argc, char** argv) -++{ -++ if (argc < 3) { -++ _usage(); -++ return 0; -++ } -++ -++ printf("%s %s\n", argv[1], argv[2]); -++ -++ BLURAY* bd = bd_open(argv[1], NULL); -++ -++ bd_get_titles(bd, TITLES_ALL, 0); -++ -++ if (!bd_start_bdj(bd, argv[2])) { -++ printf("Failed to start BD-J application.\n"); -++ } else { -++ while (1) { sleep(20); } -++ bd_stop_bdj(bd); -++ } -++ -++ bd_close(bd); -++ -++ return 0; -++} -+diff --git a/src/devtools/bdjo_dump.c b/src/devtools/bdjo_dump.c -+new file mode 100644 -+index 0000000..c9c8141 -+--- /dev/null -++++ b/src/devtools/bdjo_dump.c -+@@ -0,0 +1,206 @@ -++/* -++ * This file is part of libbluray -++ * Copyright (C) 2014 Petri Hintukainen <phintuka@users.sourceforge.net> -++ * -++ * This library is free software; you can redistribute it and/or -++ * modify it under the terms of the GNU Lesser General Public -++ * License as published by the Free Software Foundation; either -++ * version 2.1 of the License, or (at your option) any later version. -++ * -++ * This library is distributed in the hope that it will be useful, -++ * but WITHOUT ANY WARRANTY; without even the implied warranty of -++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -++ * Lesser General Public License for more details. -++ * -++ * You should have received a copy of the GNU Lesser General Public -++ * License along with this library. If not, see -++ * <http://www.gnu.org/licenses/>. -++ */ -++ -++#include "libbluray/bluray.h" -++#include "libbluray/bdj/bdjo_data.h" -++ -++#include <stdio.h> -++#include <string.h> -++ -++static const char *_yes_no(int i) -++{ -++ return i > 0 ? "yes" : i < 0 ? "unknown" : "no"; -++} -++ -++static const char *_binding_str(int i) -++{ -++ switch (i) { -++ case 0: return "unbound"; -++ case 1: return "disc bound"; -++ case 3: return "title bound"; -++ default: return "???"; -++ } -++} -++ -++static const char *_visibility_str(int i) -++{ -++ switch (i) { -++ case 0: return "none"; -++ case 1: return "applications"; -++ case 2: return "user"; -++ default: return "???"; -++ } -++} -++ -++static void _terminal_info_print(const BDJO_TERMINAL_INFO *p) -++{ -++ printf("Terminal Info:\n"); -++ printf(" Default AWT font : %s\n", p->default_font); -++ printf(" initial HaVi config : %d\n", p->initial_havi_config_id); -++ printf(" Menu call mask : %d\n", p->menu_call_mask); -++ printf(" Title search mask : %d\n", p->menu_call_mask); -++} -++ -++static void _app_cache_item_print(const BDJO_APP_CACHE_ITEM *p) -++{ -++ printf(" %3.3s: %s%s\n", -++ p->lang_code, p->ref_to_name, -++ p->type == 1 ? ".jar" : p->type == 2 ? "/" : " (unknown type)"); -++} -++ -++static void _app_cache_info_print(const BDJO_APP_CACHE_INFO *p) -++{ -++ unsigned ii; -++ -++ printf("Application cache info:\n"); -++ for (ii = 0; ii < p->num_item; ii++) { -++ _app_cache_item_print(&p->item[ii]); -++ } -++} -++ -++static void _accessible_playlists_print(const BDJO_ACCESSIBLE_PLAYLISTS *p) -++{ -++ unsigned ii; -++ -++ printf("Accessible playlists:\n"); -++ printf(" Access to all : %s\n", _yes_no(p->access_to_all_flag)); -++ printf(" Autostart first : %s\n", _yes_no(p->autostart_first_playlist_flag)); -++ -++ if (p->num_pl) { -++ printf(" Playlists : %d\n", p->num_pl); -++ for (ii = 0; ii < p->num_pl; ii++) { -++ printf(" %s.mpls\n", p->pl[ii].name); -++ } -++ } -++} -++ -++static void _app_profile_print(BDJO_APP_PROFILE *p) -++{ -++ printf(" Profile %d Version %d.%d.%d\n", -++ p->profile_number, p->major_version, p->minor_version, p->micro_version); -++} -++ -++static void _app_print(const BDJO_APP *p) -++{ -++ unsigned ii; -++ -++ printf(" Control code: : %d (%s)\n", p->control_code, -++ p->control_code == 1 ? "autostart" : p->control_code == 2 ? "present" : "???"); -++ printf(" Type : %d (%s)\n", p->type, -++ p->type == 1 ? "BD-J App" : "???"); -++ printf(" Organization ID : %08X\n", p->org_id); -++ printf(" Application ID : %04X\n", p->app_id); -++ printf(" Priority : %d\n", p->priority); -++ printf(" Binding : %d (%s)\n", p->binding, _binding_str(p->binding)); -++ printf(" Visibility : %d (%s)\n", p->visibility, _visibility_str(p->visibility)); -++ -++ if (p->num_profile) { -++ printf(" Profiles:\n"); -++ for (ii = 0; ii < p->num_profile; ii++) { -++ _app_profile_print(&p->profile[ii]); -++ } -++ } -++ -++ if (p->num_name) { -++ printf(" Names:\n"); -++ for (ii = 0; ii < p->num_name; ii++) { -++ printf(" %s: %s\n", p->name[ii].lang, p->name[ii].name); -++ } -++ } -++ -++ printf(" Base directory : %s\n", p->base_dir); -++ printf(" Icon locator : %s\n", p->icon_locator); -++ printf(" Icon flags : 0x%04x\n", p->icon_flags); -++ printf(" Classpath extension : %s\n", p->classpath_extension); -++ printf(" Initial class : %s\n", p->initial_class); -++ printf(" Parameters : "); -++ for (ii = 0; ii < p->num_param; ii++) { -++ printf("%s ", p->param[ii].param); -++ } -++ printf("\n"); -++} -++ -++static void _app_management_table_print(const BDJO_APP_MANAGEMENT_TABLE *p) -++{ -++ unsigned ii; -++ -++ for (ii = 0; ii < p->num_app; ii++) { -++ printf("Application %u:\n", ii); -++ _app_print(&p->app[ii]); -++ } -++} -++ -++static void _key_interest_table_print(const BDJO_KEY_INTEREST_TABLE *p) -++{ -++ unsigned int v; -++ memcpy(&v, p, sizeof(unsigned int)); -++ if (v) { -++ printf("Key interest table:\n"); -++ printf(" %s%s%s%s%s%s%s%s%s%s%s\n", -++ p->vk_play ? "VK_PLAY " : "", -++ p->vk_stop ? "VK_STOP " : "", -++ p->vk_ffw ? "VK_FFW " : "", -++ p->vk_rew ? "VK_REW " : "", -++ p->vk_track_next ? "VK_TRACK_NEXT " : "", -++ p->vk_track_prev ? "VK_TRACK_PREV " : "", -++ p->vk_pause ? "VK_PAUSE " : "", -++ p->vk_still_off ? "VK_STILL_OFF " : "", -++ p->vk_sec_audio_ena_dis ? "VK_SEC_AUDIO " : "", -++ p->vk_sec_video_ena_dis ? "VK_SEC_VIDEO " : "", -++ p->pg_textst_ena_dis ? "VK_PG_TEXTST " : ""); -++ } -++} -++ -++static void _file_access_info_print(const BDJO_FILE_ACCESS_INFO *p) -++{ -++ printf("File access info:\n %s\n", p->path); -++} -++ -++static void _bdjo_print(const BDJO *p) -++{ -++ _terminal_info_print(&p->terminal_info); -++ _app_cache_info_print(&p->app_cache_info); -++ _accessible_playlists_print(&p->accessible_playlists); -++ _app_management_table_print(&p->app_table); -++ _key_interest_table_print(&p->key_interest_table); -++ _file_access_info_print(&p->file_access_info); -++} -++ -++int main(int argc, const char *argv[]) -++{ -++ if (argc < 2) { -++ fprintf(stderr, "usage: %s <bdjo_file>\n", argv[0]); -++ return 1; -++ } -++ -++ int cnt; -++ for (cnt = 1; cnt < argc; cnt++) { -++ -++ printf("%s\n", argv[cnt]); -++ -++ BDJO *bdjo = bd_read_bdjo(argv[cnt]); -++ if (bdjo) { -++ _bdjo_print(bdjo); -++ bd_free_bdjo(bdjo); -++ } -++ printf("\n"); -++ } -++ -++ return 0; -++} -+diff --git a/src/devtools/clpi_dump.c b/src/devtools/clpi_dump.c -+new file mode 100644 -+index 0000000..bd64783 -+--- /dev/null -++++ b/src/devtools/clpi_dump.c -+@@ -0,0 +1,487 @@ -++/* -++ * This file is part of libbluray -++ * Copyright (C) 2009-2010 John Stebbins -++ * Copyright (C) 2012-2013 Petri Hintukainen <phintuka@users.sourceforge.net> -++ * -++ * This library is free software; you can redistribute it and/or -++ * modify it under the terms of the GNU Lesser General Public -++ * License as published by the Free Software Foundation; either -++ * version 2.1 of the License, or (at your option) any later version. -++ * -++ * This library is distributed in the hope that it will be useful, -++ * but WITHOUT ANY WARRANTY; without even the implied warranty of -++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -++ * Lesser General Public License for more details. -++ * -++ * You should have received a copy of the GNU Lesser General Public -++ * License along with this library. If not, see -++ * <http://www.gnu.org/licenses/>. -++ */ -++ -++#include <stdio.h> -++#include <stdlib.h> -++#include <unistd.h> -++#include <inttypes.h> -++ -++#include "libbluray/bdnav/clpi_data.h" -++#include "libbluray/bluray.h" -++ -++#include "util.h" -++ -++static int verbose; -++ -++typedef struct { -++ int value; -++ const char *str; -++} VALUE_MAP; -++ -++static inline const char* -++_lookup_str(const VALUE_MAP *map, int val) -++{ -++ int ii; -++ -++ for (ii = 0; map[ii].str; ii++) { -++ if (val == map[ii].value) { -++ return map[ii].str; -++ } -++ } -++ return "?"; -++} -++ -++const VALUE_MAP codec_map[] = { -++ {0x01, "MPEG-1 Video"}, -++ {0x02, "MPEG-2 Video"}, -++ {0x03, "MPEG-1 Audio"}, -++ {0x04, "MPEG-2 Audio"}, -++ {0x80, "LPCM"}, -++ {0x81, "AC-3"}, -++ {0x82, "DTS"}, -++ {0x83, "TrueHD"}, -++ {0x84, "AC-3 Plus"}, -++ {0x85, "DTS-HD"}, -++ {0x86, "DTS-HD Master"}, -++ {0xa1, "AC-3 Plus for secondary audio"}, -++ {0xa2, "DTS-HD for secondary audio"}, -++ {0xea, "VC-1"}, -++ {0x1b, "H.264"}, -++ {0x20, "H.264 MVC dep."}, -++ {0x90, "Presentation Graphics"}, -++ {0x91, "Presentation Graphics"}, -++ {0x92, "Interactive Graphics"}, -++ {0, NULL} -++}; -++ -++const VALUE_MAP video_format_map[] = { -++ {0, "Reserved"}, -++ {1, "480i"}, -++ {2, "576i"}, -++ {3, "480p"}, -++ {4, "1080i"}, -++ {5, "720p"}, -++ {6, "1080p"}, -++ {7, "576p"}, -++ {0, NULL} -++}; -++ -++const VALUE_MAP video_rate_map[] = { -++ {0, "Reserved1"}, -++ {1, "23.976"}, -++ {2, "24"}, -++ {3, "25"}, -++ {4, "29.97"}, -++ {5, "Reserved2"}, -++ {6, "50"}, -++ {7, "59.94"}, -++ {0, NULL} -++}; -++ -++const VALUE_MAP video_aspect_map[] = { -++ {0, "Reserved1"}, -++ {1, "Reserved2"}, -++ {2, "4:3"}, -++ {3, "16:9"}, -++ {0, NULL} -++}; -++ -++const VALUE_MAP audio_format_map[] = { -++ {0, "Reserved1"}, -++ {1, "Mono"}, -++ {2, "Reserved2"}, -++ {3, "Stereo"}, -++ {4, "Reserved3"}, -++ {5, "Reserved4"}, -++ {6, "Multi Channel"}, -++ {12, "Combo"}, -++ {0, NULL} -++}; -++ -++const VALUE_MAP audio_rate_map[] = { -++ {0, "Reserved1"}, -++ {1, "48 Khz"}, -++ {2, "Reserved2"}, -++ {3, "Reserved3"}, -++ {4, "96 Khz"}, -++ {5, "192 Khz"}, -++ {12, "48/192 Khz"}, -++ {14, "48/96 Khz"}, -++ {0, NULL} -++}; -++ -++const VALUE_MAP application_type_map[] = { -++ {1, "Main TS for a main-path of Movie"}, -++ {2, "Main TS for a main-path of Time based slide show"}, -++ {3, "Main TS for a main-path of Browsable slide show"}, -++ {4, "Sub TS for a sub-path of Browsable slide show"}, -++ {5, "Sub TS for a sub-path of Interactive Graphics menu"}, -++ {6, "Sub TS for a sub-path of Text subtitle"}, -++ {7, "Sub TS for a sub-path of one or more elementary streams path"}, -++ {0, NULL}, -++}; -++ -++static void -++_show_stream(CLPI_PROG_STREAM *ss, int level) -++{ -++ indent_printf(level, "Codec (%04x): %s", ss->coding_type, -++ _lookup_str(codec_map, ss->coding_type)); -++ indent_printf(level, "PID: %04x", ss->pid); -++ switch (ss->coding_type) { -++ case 0x01: -++ case 0x02: -++ case 0xea: -++ case 0x1b: -++ case 0x20: -++ indent_printf(level, "Format %02x: %s", ss->format, -++ _lookup_str(video_format_map, ss->format)); -++ indent_printf(level, "Rate %02x: %s", ss->rate, -++ _lookup_str(video_rate_map, ss->rate)); -++ indent_printf(level, "Aspect %02x: %s", ss->aspect, -++ _lookup_str(video_aspect_map, ss->aspect)); -++ indent_printf(level, "oc_flag %02x", ss->oc_flag); -++ break; -++ -++ case 0x03: -++ case 0x04: -++ case 0x80: -++ case 0x81: -++ case 0x82: -++ case 0x83: -++ case 0x84: -++ case 0x85: -++ case 0x86: -++ case 0xa1: -++ case 0xa2: -++ indent_printf(level, "Format %02x: %s", ss->format, -++ _lookup_str(audio_format_map, ss->format)); -++ indent_printf(level, "Rate %02x: %s", ss->rate, -++ _lookup_str(audio_rate_map, ss->rate)); -++ indent_printf(level, "Language: %s", ss->lang); -++ break; -++ -++ case 0x90: -++ case 0x91: -++ case 0xa0: -++ indent_printf(level, "Language: %s", ss->lang); -++ break; -++ -++ case 0x92: -++ indent_printf(level, "Char Code: %02x", ss->char_code); -++ indent_printf(level, "Language: %s", ss->lang); -++ break; -++ -++ default: -++ fprintf(stderr, "unrecognized coding type %02x\n", ss->coding_type); -++ break; -++ }; -++} -++ -++static void -++_show_clip_info(CLPI_CL *cl, int level) -++{ -++ CLPI_CLIP_INFO *ci = &cl->clip; -++ int ii; -++ -++ indent_printf(level, "Clip Info"); -++ indent_printf(level+1, "Clip Stream Type: %02x", ci->clip_stream_type); -++ indent_printf(level+1, "Clip Application Type (%02x): %s", -++ ci->application_type, _lookup_str(application_type_map, ci->application_type)); -++ indent_printf(level+1, "is_ATC_delta: %s", ci->is_atc_delta ? "True" : "False"); -++ indent_printf(level+1, "ATC delta count: %d", ci->atc_delta_count); -++ indent_printf(level+1, "TS Recording Rate: %u", ci->ts_recording_rate); -++ indent_printf(level+1, "Number Source Packets: %u", ci->num_source_packets); -++ // Show ts type info -++ indent_printf(level+1, "TS Type Info"); -++ indent_printf(level+2, "Validity Flags %02x", ci->ts_type_info.validity); -++ indent_printf(level+2, "Format Id %s", ci->ts_type_info.format_id); -++ // Show cc5 thing -++ for (ii = 0; ii < ci->atc_delta_count; ii++) { -++ indent_printf(level+1, "ATC delta[ %d ]", ii); -++ indent_printf(level+2, "Delta %08x", ci->atc_delta[ii].delta); -++ indent_printf(level+2, "File Id %s", ci->atc_delta[ii].file_id); -++ indent_printf(level+2, "File Code %s", ci->atc_delta[ii].file_code); -++ } -++ // show fonts -++ if (cl->font_info.font_count) { -++ indent_printf(level+1, "Font files"); -++ for (ii = 0; ii < cl->font_info.font_count; ii++) { -++ indent_printf(level+2, "Font file %d: %s.otf", ii+1, cl->font_info.font[ii].file_id); -++ } -++ } -++ -++ printf("\n"); -++} -++ -++static void -++_show_seq_info(CLPI_SEQ_INFO *si, int level) -++{ -++ CLPI_ATC_SEQ *atc; -++ CLPI_STC_SEQ *stc; -++ int ii, jj; -++ -++ indent_printf(level, "Sequence Info"); -++ indent_printf(level+1, "Number ATC Sequences: %d", si->num_atc_seq); -++ for (ii = 0; ii < si->num_atc_seq; ii++) { -++ atc = &si->atc_seq[ii]; -++ indent_printf(level+1, "ATC Sequence %d", ii); -++ indent_printf(level+2, "SPN ATC Start: %u", atc->spn_atc_start); -++ indent_printf(level+2, "Offset STC Id: %d", atc->offset_stc_id); -++ indent_printf(level+2, "Number STC Sequences: %d", atc->num_stc_seq); -++ for (jj = 0; jj < atc->num_stc_seq; jj++) { -++ stc = &atc->stc_seq[jj]; -++ indent_printf(level+2, "ATC Sequence %d", jj); -++ indent_printf(level+3, "SPN STC Start: %u", stc->spn_stc_start); -++ indent_printf(level+3, "PCR PID: %04x", stc->pcr_pid); -++ indent_printf(level+3, "Presentation Start: %u", -++ stc->presentation_start_time); -++ indent_printf(level+3, "Presentation End: %u", -++ stc->presentation_end_time); -++ } -++ } -++} -++ -++static void -++_show_prog_info(CLPI_PROG_INFO *pi, int level) -++{ -++ CLPI_PROG *prog; -++ int ii, jj; -++ -++ indent_printf(level, "Program Info"); -++ indent_printf(level+1, "Number Programs: %d", pi->num_prog); -++ for (ii = 0; ii < pi->num_prog; ii++) { -++ prog = &pi->progs[ii]; -++ indent_printf(level+1, "Program %d", ii); -++ indent_printf(level+2, "SPN Program Sequence Start: %d", -++ prog->spn_program_sequence_start); -++ indent_printf(level+2, "Program Map PID: %d", prog->program_map_pid); -++ indent_printf(level+2, "Number Streams: %d", prog->num_streams); -++ indent_printf(level+2, "Number Groups: %d", prog->num_groups); -++ for (jj = 0; jj < prog->num_streams; jj++) { -++ indent_printf(level+2, "Stream %d", jj); -++ _show_stream(&prog->streams[jj], level+3); -++ } -++ } -++} -++ -++static void -++_show_extent_start(CLPI_EXTENT_START *es, int level) -++{ -++ unsigned int ii; -++ -++ indent_printf(level, "Extension data: Extent Start Point"); -++ -++ if (!es->num_point) { -++ indent_printf(level+1, "(no data)"); -++ -++ } else { -++ indent_printf(level+1, "Number of Start Points: %d", es->num_point); -++ -++ if (verbose) { -++ for (ii = 0; ii < es->num_point; ii++) { -++ indent_printf(level+1, "Extent %5d: SPN 0x%08X", ii, es->point[ii]); -++ } -++ } -++ } -++} -++ -++static void -++_show_cpi_info(CLPI_CPI *cpi, int level) -++{ -++ CLPI_EP_MAP_ENTRY *entry; -++ CLPI_EP_COARSE *coarse; -++ CLPI_EP_FINE *fine; -++ int ii, jj, kk; -++ -++ indent_printf(level, "CPI"); -++ indent_printf(level+1, "Number Stream PID: %d", cpi->num_stream_pid); -++ for (ii = 0; ii < cpi->num_stream_pid; ii++) { -++ entry = &cpi->entry[ii]; -++ indent_printf(level+1, "Stream: %d", ii); -++ indent_printf(level+2, "PID: %04x", entry->pid); -++ indent_printf(level+2, "EP Stream Type: %d", entry->ep_stream_type); -++ indent_printf(level+2, "Number EP Coarse: %d", entry->num_ep_coarse); -++ indent_printf(level+2, "Number EP Fine: %d", entry->num_ep_fine); -++ indent_printf(level+2, "EP Map Start: %d", -++ entry->ep_map_stream_start_addr); -++ for (jj = 0; jj < entry->num_ep_coarse; jj++) { -++ coarse = &entry->coarse[jj]; -++ indent_printf(level+2, "Coarse: %d", jj); -++ indent_printf(level+3, "Ref EP Fine: %d", coarse->ref_ep_fine_id); -++ indent_printf(level+3, "PTS EP: %d", coarse->pts_ep); -++ indent_printf(level+3, "SPN EP: %d", coarse->spn_ep); -++ } -++ for (jj = 0; jj < entry->num_ep_fine; jj++) { -++ fine = &entry->fine[jj]; -++ indent_printf(level+2, "Fine: %d", jj); -++ indent_printf(level+3, "Angle Change Point: %s", -++ fine->is_angle_change_point ? "True":"False"); -++ indent_printf(level+3, "I End Offset: %d", -++ fine->i_end_position_offset); -++ indent_printf(level+3, "PTS EP: %d", fine->pts_ep); -++ indent_printf(level+3, "SPN EP: %d", fine->spn_ep); -++ } -++ if (verbose) { -++ uint64_t pts; -++ uint32_t spn; -++ -++ indent_printf(level+2, "PTS - SPN Map"); -++ for (jj = 0; jj < entry->num_ep_coarse; jj++) { -++ int start, end; -++ -++ indent_printf(level+3, "Coarse: %d", jj); -++ coarse = &entry->coarse[jj]; -++ start = coarse->ref_ep_fine_id; -++ if (jj < entry->num_ep_coarse - 1) { -++ end = entry->coarse[jj+1].ref_ep_fine_id; -++ } else { -++ end = entry->num_ep_fine; -++ } -++ for (kk = start; kk < end; kk++) { -++ fine = &entry->fine[kk]; -++ pts = ((uint64_t) (coarse->pts_ep & ~0x01) << 19) + -++ ((uint64_t)fine->pts_ep << 9); -++ spn = (coarse->spn_ep & ~0x1FFFF) + fine->spn_ep; -++ indent_printf(level+4, "PTS %8"PRIu64"/%8"PRIu64" -- SPN %u", -++ pts, pts >> 1, spn); -++ } -++ } -++ } -++ } -++} -++ -++ -++static void -++_usage(char *cmd) -++{ -++ fprintf(stderr, -++"Usage: %s -vcspi <clpi file> [<clpi file> ...]\n" -++"With no options, produces no output (not very useful)\n" -++"Options:\n" -++" v - Verbose output.\n" -++" c - Shows the Clip Info structure\n" -++" s - Shows the Sequence Info structure\n" -++" p - Shows the Program Info structure\n" -++" i - Shows the CPI. PTS to SPN map\n" -++" e - Shows Extent Start Table\n" -++, cmd); -++ -++ exit(EXIT_FAILURE); -++} -++ -++#define OPTS "vcspie" -++ -++int -++main(int argc, char *argv[]) -++{ -++ CLPI_CL *cl; -++ int opt; -++ int opt_clip_info = 0, opt_seq_info = 0, opt_prog_info = 0; -++ int opt_cpi_info = 0, opt_extent_start = 0; -++ int ii; -++ -++ do { -++ opt = getopt(argc, argv, OPTS); -++ switch (opt) { -++ case -1: break; -++ -++ case 'v': -++ verbose = 1; -++ break; -++ -++ case 's': -++ opt_seq_info = 1; -++ break; -++ -++ case 'i': -++ opt_cpi_info = 1; -++ break; -++ -++ case 'c': -++ opt_clip_info = 1; -++ break; -++ -++ case 'p': -++ opt_prog_info = 1; -++ break; -++ -++ case 'e': -++ opt_extent_start = 1; -++ break; -++ -++ default: -++ _usage(argv[0]); -++ break; -++ } -++ } while (opt != -1); -++ -++ if (optind >= argc) { -++ _usage(argv[0]); -++ } -++ -++ for (ii = optind; ii < argc; ii++) { -++ cl = bd_read_clpi(argv[ii]); -++ if (cl == NULL) { -++ fprintf(stderr, "Parsing %s failed\n", argv[ii]); -++ continue; -++ } -++ if (opt_clip_info) { -++ // Show clip info -++ _show_clip_info(cl, 1); -++ } -++ if (opt_seq_info) { -++ // Show sequence info -++ _show_seq_info(&cl->sequence, 1); -++ } -++ if (opt_prog_info) { -++ // Show program info -++ _show_prog_info(&cl->program, 1); -++ } -++ if (opt_cpi_info) { -++ // Show cpi -++ _show_cpi_info(&cl->cpi, 1); -++ } -++ -++ if (opt_prog_info) { -++ if (cl->program_ss.num_prog) { -++ printf("\n"); -++ indent_printf(1, "Extension: Program Info SS"); -++ _show_prog_info(&cl->program_ss, 1); -++ } -++ } -++ if (opt_cpi_info) { -++ if (cl->program_ss.num_prog) { -++ printf("\n"); -++ indent_printf(1, "Extension: CPI SS"); -++ _show_cpi_info(&cl->cpi_ss, 1); -++ } -++ } -++ if (opt_extent_start) { -++ // Show extent start point -++ if (cl->extent_start.num_point > 0) { -++ _show_extent_start(&cl->extent_start, 1); -++ } -++ } -++ -++ bd_free_clpi(cl); -++ } -++ return 0; -++} -++ -+diff --git a/src/devtools/hdmv_test.c b/src/devtools/hdmv_test.c -+new file mode 100644 -+index 0000000..585ed70 -+--- /dev/null -++++ b/src/devtools/hdmv_test.c -+@@ -0,0 +1,257 @@ -++/* -++ * This file is part of libbluray -++ * Copyright (C) 2010 hpi1 -++ * -++ * This library is free software; you can redistribute it and/or -++ * modify it under the terms of the GNU Lesser General Public -++ * License as published by the Free Software Foundation; either -++ * version 2.1 of the License, or (at your option) any later version. -++ * -++ * This library is distributed in the hope that it will be useful, -++ * but WITHOUT ANY WARRANTY; without even the implied warranty of -++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -++ * Lesser General Public License for more details. -++ * -++ * You should have received a copy of the GNU Lesser General Public -++ * License along with this library. If not, see -++ * <http://www.gnu.org/licenses/>. -++ */ -++ -++#include <stdio.h> -++#include <stdlib.h> -++#include <string.h> -++#include <inttypes.h> -++ -++#include "util/log_control.h" -++#include "libbluray/bluray.h" -++ -++static void _print_event(BD_EVENT *ev) -++{ -++ switch (ev->event) { -++ case BD_EVENT_NONE: -++ break; -++ case BD_EVENT_ERROR: -++ printf("EVENT_ERROR:\t%d\n", ev->param); -++ break; -++ case BD_EVENT_READ_ERROR: -++ printf("EVENT_READ_ERROR:\t%d\n", ev->param); -++ break; -++ case BD_EVENT_ENCRYPTED: -++ printf("EVENT_ENCRYPTED:\t%d\n", ev->param); -++ break; -++ -++ /* current playback position */ -++ -++ case BD_EVENT_ANGLE: -++ printf("EVENT_ANGLE:\t%d\n", ev->param); -++ break; -++ case BD_EVENT_TITLE: -++ printf("EVENT_TITLE:\t%d\n", ev->param); -++ break; -++ case BD_EVENT_PLAYLIST: -++ printf("EVENT_PLAYLIST:\t%d\n", ev->param); -++ break; -++ case BD_EVENT_PLAYITEM: -++ printf("EVENT_PLAYITEM:\t%d\n", ev->param); -++ break; -++ case BD_EVENT_CHAPTER: -++ printf("EVENT_CHAPTER:\t%d\n", ev->param); -++ break; -++ -++ /* */ -++ -++ case BD_EVENT_STILL: -++ printf("EVENT_STILL:\t%d\n", ev->param); -++ break; -++ -++ case BD_EVENT_SEEK: -++ printf("EVENT_SEEK:\t%d\n", ev->param); -++ break; -++ -++ case BD_EVENT_STILL_TIME: -++ if (ev->param) { -++ printf("EVENT_STILL_TIME:\t%d\n", ev->param); -++ } else { -++ printf("EVENT_STILL_TIME:\tinfinite\n"); -++ } -++ break; -++ -++ /* stream selection */ -++ -++ case BD_EVENT_AUDIO_STREAM: -++ printf("EVENT_AUDIO_STREAM:\t%d\n", ev->param); -++ break; -++ case BD_EVENT_IG_STREAM: -++ printf("EVENT_IG_STREAM:\t%d\n", ev->param); -++ break; -++ case BD_EVENT_PG_TEXTST_STREAM: -++ printf("EVENT_PG_TEXTST_STREAM:\t%d\n", ev->param); -++ break; -++ case BD_EVENT_SECONDARY_AUDIO_STREAM: -++ printf("EVENT_SECONDARY_AUDIO_STREAM:\t%d\n", ev->param); -++ break; -++ case BD_EVENT_SECONDARY_VIDEO_STREAM: -++ printf("EVENT_SECONDARY_VIDEO_STREAM:\t%d\n", ev->param); -++ break; -++ -++ case BD_EVENT_PG_TEXTST: -++ printf("EVENT_PG_TEXTST:\t%s\n", ev->param ? "enable" : "disable"); -++ break; -++ case BD_EVENT_SECONDARY_AUDIO: -++ printf("EVENT_SECONDARY_AUDIO:\t%s\n", ev->param ? "enable" : "disable"); -++ break; -++ case BD_EVENT_SECONDARY_VIDEO: -++ printf("EVENT_SECONDARY_VIDEO:\t%s\n", ev->param ? "enable" : "disable"); -++ break; -++ case BD_EVENT_SECONDARY_VIDEO_SIZE: -++ printf("EVENT_SECONDARY_VIDEO_SIZE:\t%s\n", ev->param==0 ? "PIP" : "fullscreen"); -++ break; -++ -++ default: -++ printf("UNKNOWN EVENT %d:\t%d\n", ev->event, ev->param); -++ break; -++ } -++ -++ fflush(stdout); -++} -++ -++static void _read_to_eof(BLURAY *bd) -++{ -++ BD_EVENT ev; -++ int bytes; -++ uint64_t total = 0; -++ uint8_t buf[6144]; -++ -++ bd_seek(bd, bd_get_title_size(bd) - 6144); -++ -++ do { -++ bytes = bd_read_ext(bd, buf, 6144, &ev); -++ total += bytes < 0 ? 0 : bytes; -++ _print_event(&ev); -++ } while (bytes > 0); -++ -++ printf("_read_to_eof(): read %"PRIu64" bytes\n", total); -++} -++ -++static void _print_events(BLURAY *bd) -++{ -++ BD_EVENT ev; -++ -++ do { -++ bd_read_ext(bd, NULL, 0, &ev); -++ _print_event(&ev); -++ } while (ev.event != BD_EVENT_NONE && ev.event != BD_EVENT_ERROR); -++} -++ -++static void _play_pl(BLURAY *bd) -++{ -++ printf("Playing playlist\n"); -++ -++ fflush(stdout); -++ _read_to_eof(bd); -++ -++ printf("Playing playlist done\n\n"); -++ -++ _print_events(bd); -++ -++ printf("\n"); -++} -++ -++int main(int argc, char *argv[]) -++{ -++ int title = -1; -++ int verbose = 0; -++ int args = 0; -++ -++ /* -++ * parse arguments -++ */ -++ -++ if (argc < 2) { -++ printf("\nUsage:\n %s [-v] [-t <title>] <media_path> [<keyfile_path>]\n\n", argv[0]); -++ return -1; -++ } -++ -++ if (!strcmp(argv[1+args], "-v")) { -++ verbose = 1; -++ args++; -++ } -++ -++ if (!strcmp(argv[1+args], "-t")) { -++ args++; -++ title = atoi(argv[1+args]); -++ args++; -++ printf("Requested title %d\n", title); -++ } -++ -++ if (verbose) { -++ printf("Enabling verbose debug\n"); -++ bd_set_debug_mask(bd_get_debug_mask() | DBG_HDMV | DBG_BLURAY); -++ } -++ -++ printf("\n"); -++ -++ /* -++ * open and setup -++ */ -++ -++ BLURAY *bd = bd_open(argv[1+args], argv[2+args]); -++ -++ if (!bd) { -++ printf("bd_open(\'%s\') failed\n", argv[1]); -++ return -1; -++ } -++ -++ bd_set_player_setting (bd, BLURAY_PLAYER_SETTING_PARENTAL, 99); -++ bd_set_player_setting_str(bd, BLURAY_PLAYER_SETTING_AUDIO_LANG, "eng"); -++ bd_set_player_setting_str(bd, BLURAY_PLAYER_SETTING_PG_LANG, "eng"); -++ bd_set_player_setting_str(bd, BLURAY_PLAYER_SETTING_MENU_LANG, "eng"); -++ bd_set_player_setting_str(bd, BLURAY_PLAYER_SETTING_COUNTRY_CODE, NULL); -++ -++ /* -++ * play -++ */ -++ -++ printf("Running first play movie object\n"); -++ -++ fflush(stdout); -++ bd_play(bd); -++ -++ _print_events(bd); -++ -++ printf("\n"); -++ -++ /* -++ * play title -++ */ -++ -++ if (title >= 0) { -++ printf("Playing title %d\n", title); -++ -++ fflush(stdout); -++ bd_play_title(bd, title); -++ -++ _print_events(bd); -++ -++ printf("\n"); -++ } -++ -++ /* -++ * play playlist -++ */ -++ -++ _play_pl(bd); -++ -++ _play_pl(bd); -++ -++ _play_pl(bd); -++ -++ /* -++ * clean up -++ */ -++ -++ bd_close(bd); -++ -++ return 0; -++} -++ -+diff --git a/src/devtools/mobj_dump.c b/src/devtools/mobj_dump.c -+new file mode 100644 -+index 0000000..3eaf9f4 -+--- /dev/null -++++ b/src/devtools/mobj_dump.c -+@@ -0,0 +1,83 @@ -++/* -++ * This file is part of libbluray -++ * Copyright (C) 2010 hpi1 -++ * -++ * This library is free software; you can redistribute it and/or -++ * modify it under the terms of the GNU Lesser General Public -++ * License as published by the Free Software Foundation; either -++ * version 2.1 of the License, or (at your option) any later version. -++ * -++ * This library is distributed in the hope that it will be useful, -++ * but WITHOUT ANY WARRANTY; without even the implied warranty of -++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -++ * Lesser General Public License for more details. -++ * -++ * You should have received a copy of the GNU Lesser General Public -++ * License along with this library. If not, see -++ * <http://www.gnu.org/licenses/>. -++ */ -++ -++#include "libbluray/bluray.h" -++ -++#include "libbluray/hdmv/mobj_data.h" -++#include "libbluray/hdmv/mobj_print.h" -++ -++#include <stdio.h> -++#include <string.h> -++ -++static void _mobj_print(MOBJ_OBJECTS *objects, int disasm) -++{ -++ int o, c; -++ -++ printf("Number of objects: %d\n", objects->num_objects); -++ -++ for (o = 0; o < objects->num_objects; o++) { -++ -++ printf("Object %d:\n" -++ " number of commands: %d\n" -++ " resume intention flag: %d\n" -++ " menu call mask: %d\n" -++ " title search mask: %d\n", -++ o, objects->objects[o].num_cmds, -++ objects->objects[o].resume_intention_flag, -++ objects->objects[o].menu_call_mask, -++ objects->objects[o].title_search_mask); -++ -++ if (disasm) { -++ printf(" program:\n"); -++ for (c = 0; c < objects->objects[o].num_cmds; c++) { -++ char buf[256]; -++ mobj_sprint_cmd(buf, &objects->objects[o].cmds[c]); -++ printf(" %04d: %s\n", c, buf); -++ } -++ } -++ } -++} -++ -++int main(int argc, const char *argv[]) -++{ -++ int disasm = 0; -++ MOBJ_OBJECTS *mobj = NULL; -++ -++ if (argc < 2) { -++ fprintf(stderr, -++ "usage: %s [-d] <file>\n" -++ "Options:\n" -++ " d disassemble object code\n", -++ argv[0]); -++ return 1; -++ } -++ if (argc > 2) { -++ disasm = !strcmp(argv[1], "-d"); -++ } -++ -++ mobj = bd_read_mobj(argv[argc-1]); -++ -++ if (mobj) { -++ _mobj_print(mobj, disasm); -++ -++ bd_free_mobj(mobj); -++ } -++ -++ return 0; -++} -+diff --git a/src/devtools/mpls_dump.c b/src/devtools/mpls_dump.c -+new file mode 100644 -+index 0000000..405b6a1 -+--- /dev/null -++++ b/src/devtools/mpls_dump.c -+@@ -0,0 +1,799 @@ -++/* -++ * This file is part of libbluray -++ * Copyright (C) 2009-2010 John Stebbins -++ * -++ * This library is free software; you can redistribute it and/or -++ * modify it under the terms of the GNU Lesser General Public -++ * License as published by the Free Software Foundation; either -++ * version 2.1 of the License, or (at your option) any later version. -++ * -++ * This library is distributed in the hope that it will be useful, -++ * but WITHOUT ANY WARRANTY; without even the implied warranty of -++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -++ * Lesser General Public License for more details. -++ * -++ * You should have received a copy of the GNU Lesser General Public -++ * License along with this library. If not, see -++ * <http://www.gnu.org/licenses/>. -++ */ -++ -++#include <sys/stat.h> -++#include <dirent.h> -++#include <stdio.h> -++#include <stdlib.h> -++#include <unistd.h> -++#include <string.h> -++#include <libgen.h> -++ -++#include "libbluray/bdnav/mpls_parse.h" -++#include "libbluray/bluray.h" -++ -++#include "util.h" -++ -++#ifdef _WIN32 -++# define DIR_SEP "\\" -++# define PLAYLIST_DIR "\\BDMV\\PLAYLIST" -++#else -++# define DIR_SEP "/" -++# define PLAYLIST_DIR "/BDMV/PLAYLIST" -++#endif -++ -++ -++static int verbose; -++ -++typedef struct { -++ int value; -++ const char *str; -++} VALUE_MAP; -++ -++const VALUE_MAP codec_map[] = { -++ {0x01, "MPEG-1 Video"}, -++ {0x02, "MPEG-2 Video"}, -++ {0x03, "MPEG-1 Audio"}, -++ {0x04, "MPEG-2 Audio"}, -++ {0x80, "LPCM"}, -++ {0x81, "AC-3"}, -++ {0x82, "DTS"}, -++ {0x83, "TrueHD"}, -++ {0x84, "AC-3 Plus"}, -++ {0x85, "DTS-HD"}, -++ {0x86, "DTS-HD Master"}, -++ {0xa1, "AC-3 Plus for secondary audio"}, -++ {0xa2, "DTS-HD for secondary audio"}, -++ {0xea, "VC-1"}, -++ {0x1b, "H.264"}, -++ {0x90, "Presentation Graphics"}, -++ {0x91, "Interactive Graphics"}, -++ {0x92, "Text Subtitle"}, -++ {0, NULL} -++}; -++ -++const VALUE_MAP video_format_map[] = { -++ {0, "Reserved"}, -++ {1, "480i"}, -++ {2, "576i"}, -++ {3, "480p"}, -++ {4, "1080i"}, -++ {5, "720p"}, -++ {6, "1080p"}, -++ {7, "576p"}, -++ {0, NULL} -++}; -++ -++const VALUE_MAP video_rate_map[] = { -++ {0, "Reserved1"}, -++ {1, "23.976"}, -++ {2, "24"}, -++ {3, "25"}, -++ {4, "29.97"}, -++ {5, "Reserved2"}, -++ {6, "50"}, -++ {7, "59.94"}, -++ {0, NULL} -++}; -++ -++const VALUE_MAP audio_format_map[] = { -++ {0, "Reserved1"}, -++ {1, "Mono"}, -++ {2, "Reserved2"}, -++ {3, "Stereo"}, -++ {4, "Reserved3"}, -++ {5, "Reserved4"}, -++ {6, "Multi Channel"}, -++ {12, "Combo"}, -++ {0, NULL} -++}; -++ -++const VALUE_MAP audio_rate_map[] = { -++ {0, "Reserved1"}, -++ {1, "48 Khz"}, -++ {2, "Reserved2"}, -++ {3, "Reserved3"}, -++ {4, "96 Khz"}, -++ {5, "192 Khz"}, -++ {12, "48/192 Khz"}, -++ {14, "48/96 Khz"}, -++ {0, NULL} -++}; -++ -++const VALUE_MAP subpath_type_map[] = { -++ {2, "Primary audio of the Browsable slideshow"}, -++ {3, "Interactive Graphics presentation menu"}, -++ {4, "Text Subtitle"}, -++ {5, "Out-of-mux Synchronous elementary streams"}, -++ {6, "Out-of-mux Asynchronous Picture-in-Picture presentation"}, -++ {7, "In-mux Synchronous Picture-in-Picture presentation"}, -++ {8, "SS Video"}, -++ {0,NULL} -++}; -++ -++const VALUE_MAP playback_type_map[] = { -++ {1, "Sequential"}, -++ {2, "Random"}, -++ {3, "Shuffle"}, -++ {0, NULL} -++}; -++ -++const VALUE_MAP connection_type_map[] = { -++ {1, "Non-seamless"}, -++ {5, "Seamless"}, -++ {6, "Seamless"}, -++ {0, NULL} -++}; -++ -++static const char* -++_lookup_str(const VALUE_MAP *map, int val) -++{ -++ int ii; -++ -++ for (ii = 0; map[ii].str; ii++) { -++ if (val == map[ii].value) { -++ return map[ii].str; -++ } -++ } -++ return "?"; -++} -++ -++static char * -++_mk_path(const char *base, const char *sub) -++{ -++ size_t n1 = strlen(base); -++ size_t n2 = strlen(sub); -++ char *result = (char*)malloc(n1 + n2 + strlen(DIR_SEP) + 1); -++ strcpy(result, base); -++ strcat(result, DIR_SEP); -++ strcat(result, sub); -++ -++ return result; -++} -++ -++static void -++_show_stream(MPLS_STREAM *ss, int level) -++{ -++ indent_printf(level, "Codec (%04x): %s", ss->coding_type, -++ _lookup_str(codec_map, ss->coding_type)); -++ switch (ss->stream_type) { -++ case 1: -++ indent_printf(level, "PID: %04x", ss->pid); -++ break; -++ -++ case 2: -++ case 4: -++ indent_printf(level, "SubPath Id: %02x", ss->subpath_id); -++ indent_printf(level, "SubClip Id: %02x", ss->subclip_id); -++ indent_printf(level, "PID: %04x", ss->pid); -++ break; -++ -++ case 3: -++ indent_printf(level, "SubPath Id: %02x", ss->subpath_id); -++ indent_printf(level, "PID: %04x", ss->pid); -++ break; -++ -++ default: -++ fprintf(stderr, "unrecognized stream type %02x\n", ss->stream_type); -++ break; -++ }; -++ -++ switch (ss->coding_type) { -++ case 0x01: -++ case 0x02: -++ case 0xea: -++ case 0x1b: -++ indent_printf(level, "Format %02x: %s", ss->format, -++ _lookup_str(video_format_map, ss->format)); -++ indent_printf(level, "Rate %02x: %s", ss->rate, -++ _lookup_str(video_rate_map, ss->rate)); -++ break; -++ -++ case 0x03: -++ case 0x04: -++ case 0x80: -++ case 0x81: -++ case 0x82: -++ case 0x83: -++ case 0x84: -++ case 0x85: -++ case 0x86: -++ case 0xa1: -++ case 0xa2: -++ indent_printf(level, "Format %02x: %s", ss->format, -++ _lookup_str(audio_format_map, ss->format)); -++ indent_printf(level, "Rate %02x: %s", ss->rate, -++ _lookup_str(audio_rate_map, ss->rate)); -++ indent_printf(level, "Language: %s", ss->lang); -++ break; -++ -++ case 0x90: -++ case 0x91: -++ indent_printf(level, "Language: %s", ss->lang); -++ break; -++ -++ case 0x92: -++ indent_printf(level, "Char Code: %02x", ss->char_code); -++ indent_printf(level, "Language: %s", ss->lang); -++ break; -++ -++ default: -++ fprintf(stderr, "unrecognized coding type %02x\n", ss->coding_type); -++ break; -++ }; -++} -++ -++static void -++_show_details(MPLS_PL *pl, int level) -++{ -++ int ii, jj, kk; -++ -++ for (ii = 0; ii < pl->list_count; ii++) { -++ MPLS_PI *pi; -++ -++ pi = &pl->play_item[ii]; -++ indent_printf(level, "Clip Id %s", pi->clip[0].clip_id); -++ indent_printf(level+1, "Stc Id: %02x", pi->clip[0].stc_id); -++ indent_printf(level+1, "Connection Condition: %s (%02x)", -++ _lookup_str(connection_type_map, pi->connection_condition), -++ pi->connection_condition); -++ indent_printf(level+1, "In-Time: %d", pi->in_time); -++ indent_printf(level+1, "Out-Time: %d", pi->out_time); -++ if (pi->still_mode == 1) { -++ indent_printf(level+1, "Still time: %ds\n", pi->still_time); -++ } -++ if (pi->still_mode == 2) { -++ indent_printf(level+1, "Still time: infinite\n"); -++ } -++ if (pi->angle_count > 1) { -++ for (jj = 1; jj < pi->angle_count; jj++) { -++ indent_printf(level+1, "Angle %d:", jj); -++ indent_printf(level+2, "Clip Id %s", pi->clip[jj].clip_id); -++ indent_printf(level+2, "Stc Id: %02x", pi->clip[jj].stc_id); -++ } -++ } -++ for (jj = 0; jj < pi->stn.num_video; jj++) { -++ indent_printf(level+1, "Video Stream %d:", jj); -++ _show_stream(&pi->stn.video[jj], level + 2); -++ } -++ for (jj = 0; jj < pi->stn.num_audio; jj++) { -++ indent_printf(level+1, "Audio Stream %d:", jj); -++ _show_stream(&pi->stn.audio[jj], level + 2); -++ } -++ for (jj = 0; jj < pi->stn.num_ig; jj++) { -++ indent_printf(level+1, "Interactive Graphics Stream %d:", jj); -++ _show_stream(&pi->stn.ig[jj], level + 2); -++ } -++ for (jj = 0; jj < (pi->stn.num_pg + pi->stn.num_pip_pg); jj++) { -++ if (jj < pi->stn.num_pg) { -++ indent_printf(level+1, "Presentation Graphics Stream %d:", jj); -++ } else { -++ indent_printf(level+1, "PIP Presentation Graphics Stream %d:", jj); -++ } -++ _show_stream(&pi->stn.pg[jj], level + 2); -++ } -++ for (jj = 0; jj < pi->stn.num_secondary_video; jj++) { -++ indent_printf(level+1, "Secondary Video Stream %d:", jj); -++ _show_stream(&pi->stn.secondary_video[jj], level + 2); -++ for (kk = 0; kk < pi->stn.secondary_video[jj].sv_num_secondary_audio_ref; kk++) { -++ indent_printf(level+2, "Secondary Audio Ref %d: %d", kk,pi->stn.secondary_video[jj].sv_secondary_audio_ref[kk]); -++ } -++ for (kk = 0; kk < pi->stn.secondary_video[jj].sv_num_pip_pg_ref; kk++) { -++ indent_printf(level+2, "PIP Presentation Graphic Ref %d: %d", kk,pi->stn.secondary_video[jj].sv_pip_pg_ref[kk]); -++ } -++ } -++ for (jj = 0; jj < pi->stn.num_secondary_audio; jj++) { -++ indent_printf(level+1, "Secondary Audio Stream %d:", jj); -++ _show_stream(&pi->stn.secondary_audio[jj], level + 2); -++ for (kk = 0; kk < pi->stn.secondary_audio[jj].sa_num_primary_audio_ref; kk++) { -++ indent_printf(level+2, "Primary Audio Ref %d: %d", kk,pi->stn.secondary_audio[jj].sa_primary_audio_ref[kk]); -++ } -++ } -++ printf("\n"); -++ } -++} -++ -++static void -++_show_ai(MPLS_PL *pl, int level) -++{ -++ indent_printf(level, "Playback type: %s (%d)", -++ _lookup_str(playback_type_map, pl->app_info.playback_type), -++ pl->app_info.playback_type); -++ if (pl->app_info.playback_type == 2 || pl->app_info.playback_type == 3) { -++ indent_printf(level+1, "Playback count: %d", pl->app_info.playback_count); -++ } -++} -++ -++static void -++_show_marks(MPLS_PL *pl, int level) -++{ -++ int ii; -++ -++ indent_printf(level, "PlayMark Count %d", pl->mark_count); -++ for (ii = 0; ii < pl->mark_count; ii++) { -++ MPLS_PI *pi; -++ MPLS_PLM *plm; -++ int min; -++ double sec; -++ -++ plm = &pl->play_mark[ii]; -++ indent_printf(level, "PlayMark %d", ii); -++ indent_printf(level+1, "Type: %02x", plm->mark_type); -++ if (plm->play_item_ref < pl->list_count) { -++ pi = &pl->play_item[plm->play_item_ref]; -++ indent_printf(level+1, "PlayItem: %s", pi->clip[0].clip_id); -++ } else { -++ indent_printf(level+1, "PlayItem: Invalid reference"); -++ } -++ indent_printf(level+1, "Time (ticks): %u", plm->time); -++ min = plm->duration / (45000*60); -++ sec = (double)(plm->duration - min * 45000 * 60) / 45000; -++ indent_printf(level+1, "Duration (mm:ss.ms, ticks): %d:%.2f, %u", -++ min, sec, plm->duration); -++ printf("\n"); -++ } -++} -++ -++static void -++_show_clip_list(MPLS_PL *pl, int level) -++{ -++ int ii, jj; -++ -++ for (ii = 0; ii < pl->list_count; ii++) { -++ MPLS_PI *pi; -++ -++ pi = &pl->play_item[ii]; -++ if (verbose) { -++ uint32_t duration; -++ -++ duration = pi->out_time - pi->in_time; -++ indent_printf(level, "%s.m2ts -- Duration: %3d:%02d", -++ pi->clip[0].clip_id, -++ duration / (45000 * 60), (duration / 45000) % 60); -++ } else { -++ indent_printf(level, "%s.m2ts", pi->clip[0].clip_id); -++ } -++ if (pi->angle_count > 1) { -++ for (jj = 1; jj < pi->angle_count; jj++) { -++ indent_printf(level+1, "Angle %d: %s.m2ts", jj+1, pi->clip[jj].clip_id); -++ } -++ } -++ } -++ printf("\n"); -++} -++ -++static void -++_show_sub_path(MPLS_SUB *sub, int level) -++{ -++ int ii; -++ -++ indent_printf(level+1, "Type: %d (%s)", sub->type, _lookup_str(subpath_type_map, sub->type)); -++ indent_printf(level+1, "Repeat: %d", sub->is_repeat); -++ indent_printf(level+1, "Sub playitem count: %d", sub->sub_playitem_count); -++ -++ for (ii = 0; ii < sub->sub_playitem_count; ii++) { -++ MPLS_SUB_PI *pi; -++ -++ pi = &sub->sub_play_item[ii]; -++ -++ if (verbose) { -++ indent_printf(level+1, "Sub playitem %d", ii); -++ indent_printf(level+2, "Clip Id %s", pi->clip[0].clip_id); -++ indent_printf(level+2, "Multi clip: %d", pi->is_multi_clip); -++ indent_printf(level+2, "Clip count: %d", pi->clip_count); -++ indent_printf(level+2, "Connection Condition: %s (%02x)", -++ _lookup_str(connection_type_map, pi->connection_condition), -++ pi->connection_condition); -++ indent_printf(level+2, "In-Time: %d", pi->in_time); -++ indent_printf(level+2, "Out-Time: %d", pi->out_time); -++ indent_printf(level+2, "Sync playitem Id: %d", pi->sync_play_item_id); -++ indent_printf(level+2, "Sync PTS: %d", pi->sync_pts); -++ } else { -++ indent_printf(level+1, "%s.m2ts", pi->clip[0].clip_id); -++ } -++ } -++} -++ -++static void -++_show_pip_metadata_block(MPLS_PIP_METADATA *block, int level) -++{ -++ int ii; -++ -++ indent_printf(level, "Clip ref: %d", block->clip_ref); -++ indent_printf(level, "Secondary video ref: %d", block->secondary_video_ref); -++ indent_printf(level, "Timeline type: %d", block->timeline_type); -++ indent_printf(level, "Luma key flag: %d", block->luma_key_flag); -++ if (block->luma_key_flag) { -++ indent_printf(level, "Upper limit luma key: %d", block->upper_limit_luma_key); -++ } -++ indent_printf(level, "Trick play flag: %d", block->trick_play_flag); -++ -++ for (ii = 0; ii < block->data_count; ii++) { -++ indent_printf(level, "data block %d:", ii); -++ indent_printf(level+1, "Timestamp: %d", block->data[ii].time); -++ indent_printf(level+1, "Horizontal position %d", block->data[ii].xpos); -++ indent_printf(level+1, "Vertical position: %d", block->data[ii].ypos); -++ indent_printf(level+1, "Scaling factor: %d", block->data[ii].scale_factor); -++ } -++} -++ -++static void -++_show_pip_metadata(MPLS_PL *pl, int level) -++{ -++ int ii; -++ -++ for (ii = 0; ii < pl->ext_pip_data_count; ii++) { -++ MPLS_PIP_METADATA *data; -++ -++ data = &pl->ext_pip_data[ii]; -++ -++ indent_printf(level, "PiP metadata block %d:", ii); -++ _show_pip_metadata_block(data, level+1); -++ } -++} -++ -++static void -++_show_sub_paths(MPLS_PL *pl, int level) -++{ -++ int ss; -++ -++ for (ss = 0; ss < pl->sub_count; ss++) { -++ MPLS_SUB *sub; -++ -++ sub = &pl->sub_path[ss]; -++ -++ indent_printf(level, "Sub Path %d:", ss); -++ _show_sub_path(sub, level+1); -++ } -++} -++ -++static void -++_show_sub_paths_ss(MPLS_PL *pl, int level) -++{ -++ int ss; -++ -++ for (ss = 0; ss < pl->ext_sub_count; ss++) { -++ MPLS_SUB *sub; -++ -++ sub = &pl->ext_sub_path[ss]; -++ -++ indent_printf(level, "Extension Sub Path %d:", ss); -++ _show_sub_path(sub, level+1); -++ } -++} -++ -++static uint32_t -++_pl_duration(MPLS_PL *pl) -++{ -++ int ii; -++ uint32_t duration = 0; -++ MPLS_PI *pi; -++ -++ for (ii = 0; ii < pl->list_count; ii++) { -++ pi = &pl->play_item[ii]; -++ duration += pi->out_time - pi->in_time; -++ } -++ return duration; -++} -++ -++static int -++_filter_dup(MPLS_PL *pl_list[], int count, MPLS_PL *pl) -++{ -++ int ii, jj; -++ -++ for (ii = 0; ii < count; ii++) { -++ if (pl->list_count != pl_list[ii]->list_count || -++ _pl_duration(pl) != _pl_duration(pl_list[ii])) { -++ continue; -++ } -++ for (jj = 0; jj < pl->list_count; jj++) { -++ MPLS_PI *pi1, *pi2; -++ -++ pi1 = &pl->play_item[jj]; -++ pi2 = &pl_list[ii]->play_item[jj]; -++ -++ if (memcmp(pi1->clip[0].clip_id, pi2->clip[0].clip_id, 5) != 0 || -++ pi1->in_time != pi2->in_time || -++ pi1->out_time != pi2->out_time) { -++ break; -++ } -++ } -++ if (jj != pl->list_count) { -++ continue; -++ } -++ return 0; -++ } -++ return 1; -++} -++ -++static int -++_find_repeats(MPLS_PL *pl, const char *m2ts) -++{ -++ int ii, count = 0; -++ -++ for (ii = 0; ii < pl->list_count; ii++) { -++ MPLS_PI *pi; -++ -++ pi = &pl->play_item[ii]; -++ // Ignore titles with repeated segments -++ if (strcmp(pi->clip[0].clip_id, m2ts) == 0) { -++ count++; -++ } -++ } -++ return count; -++} -++ -++static int -++_filter_short(MPLS_PL *pl, unsigned int seconds) -++{ -++ // Ignore short playlists -++ if (_pl_duration(pl) / 45000 <= seconds) { -++ return 0; -++ } -++ return 1; -++} -++ -++static int -++_filter_repeats(MPLS_PL *pl, int repeats) -++{ -++ int ii; -++ -++ for (ii = 0; ii < pl->list_count; ii++) { -++ MPLS_PI *pi; -++ -++ pi = &pl->play_item[ii]; -++ // Ignore titles with repeated segments -++ if (_find_repeats(pl, pi->clip[0].clip_id) > repeats) { -++ return 0; -++ } -++ } -++ return 1; -++} -++ -++static int clip_list = 0, playlist_info = 0, chapter_marks = 0, sub_paths = 0, pip_metadata = 0; -++static int repeats = 0, seconds = 0, dups = 0; -++ -++static MPLS_PL* -++_process_file(char *name, MPLS_PL *pl_list[], int pl_count) -++{ -++ MPLS_PL *pl; -++ -++ pl = bd_read_mpls(name); -++ if (pl == NULL) { -++ fprintf(stderr, "Parse failed: %s\n", name); -++ return NULL; -++ } -++ if (seconds) { -++ if (!_filter_short(pl, seconds)) { -++ bd_free_mpls(pl); -++ return NULL; -++ } -++ } -++ if (repeats) { -++ if (!_filter_repeats(pl, repeats)) { -++ bd_free_mpls(pl); -++ return NULL; -++ } -++ } -++ if (dups) { -++ if (!_filter_dup(pl_list, pl_count, pl)) { -++ bd_free_mpls(pl); -++ return NULL; -++ } -++ } -++ if (verbose) { -++ indent_printf(0, -++ "%s -- Num Clips: %3d , Duration: minutes %4u:%02u", -++ basename(name), -++ pl->list_count, -++ _pl_duration(pl) / (45000 * 60), -++ (_pl_duration(pl) / 45000) % 60); -++ _show_ai(pl, 1); -++ } else { -++ indent_printf(0, "%s -- Duration: minutes %4u:%02u", -++ basename(name), -++ _pl_duration(pl) / (45000 * 60), -++ (_pl_duration(pl) / 45000) % 60); -++ } -++ if (playlist_info) { -++ _show_details(pl, 1); -++ } -++ if (chapter_marks) { -++ _show_marks(pl, 1); -++ } -++ if (pip_metadata) { -++ _show_pip_metadata(pl, 1); -++ } -++ if (clip_list) { -++ _show_clip_list(pl, 1); -++ } -++ if (sub_paths) { -++ _show_sub_paths(pl, 1); -++ _show_sub_paths_ss(pl, 1); -++ } -++ return pl; -++} -++ -++static void -++_usage(char *cmd) -++{ -++ fprintf(stderr, -++"Usage: %s -vli <mpls file> [<mpls file> ...]\n" -++"With no options, produces a list of the playlist(s) with durations\n" -++"Options:\n" -++" v - Verbose output.\n" -++" l - Produces a list of the m2ts clips\n" -++" i - Dumps detailed information about each clip\n" -++" c - Show chapter marks\n" -++" p - Show sub paths\n" -++" P - Show picture-in-picture metadata\n" -++" r <N> - Filter out titles that have >N repeating clips\n" -++" d - Filter out duplicate titles\n" -++" s <seconds> - Filter out short titles\n" -++" f - Filter combination -r2 -d -s900\n" -++, cmd); -++ -++ exit(EXIT_FAILURE); -++} -++ -++#define OPTS "vlicpPfr:ds:" -++ -++static int -++_qsort_str_cmp(const void *a, const void *b) -++{ -++ const char *stra = *(char * const *)a; -++ const char *strb = *(char * const *)b; -++ -++ return strcmp(stra, strb); -++} -++ -++int -++main(int argc, char *argv[]) -++{ -++ MPLS_PL *pl; -++ int opt; -++ int ii, pl_ii; -++ MPLS_PL *pl_list[1000]; -++ struct stat st; -++ char *path = NULL; -++ DIR *dir = NULL; -++ -++ do { -++ opt = getopt(argc, argv, OPTS); -++ switch (opt) { -++ case -1: -++ break; -++ -++ case 'v': -++ verbose = 1; -++ break; -++ -++ case 'l': -++ clip_list = 1; -++ break; -++ -++ case 'i': -++ playlist_info = 1; -++ break; -++ -++ case 'c': -++ chapter_marks = 1; -++ break; -++ -++ case 'p': -++ sub_paths = 1; -++ break; -++ -++ case 'P': -++ pip_metadata = 1; -++ break; -++ -++ case 'd': -++ dups = 1; -++ break; -++ -++ case 'r': -++ repeats = atoi(optarg); -++ break; -++ -++ case 'f': -++ repeats = 2; -++ dups = 1; -++ seconds = 900; -++ break; -++ -++ case 's': -++ seconds = atoi(optarg); -++ break; -++ -++ default: -++ _usage(argv[0]); -++ break; -++ } -++ } while (opt != -1); -++ -++ if (optind >= argc) { -++ _usage(argv[0]); -++ } -++ -++ for (pl_ii = 0, ii = optind; pl_ii < 1000 && ii < argc; ii++) { -++ -++ if (stat(argv[ii], &st)) { -++ continue; -++ } -++ dir = NULL; -++ if (S_ISDIR(st.st_mode)) { -++ -++ printf("Directory: %s:\n", argv[ii]); -++ path = _mk_path(argv[ii], PLAYLIST_DIR); -++ if (path == NULL) { -++ fprintf(stderr, "Failed to find playlist path: %s\n", argv[ii]); -++ continue; -++ } -++ dir = opendir(path); -++ if (dir == NULL) { -++ fprintf(stderr, "Failed to open dir: %s\n", path); -++ free(path); -++ continue; -++ } -++ } -++ if (dir != NULL) { -++ char **dirlist = (char**)calloc(10001, sizeof(char*)); -++ struct dirent *ent; -++ int jj = 0; -++ for (ent = readdir(dir); ent != NULL; ent = readdir(dir)) { -++ dirlist[jj++] = strcpy((char*)malloc(strlen(ent->d_name)), ent->d_name); -++ } -++ qsort(dirlist, jj, sizeof(char*), _qsort_str_cmp); -++ for (jj = 0; dirlist[jj] != NULL; jj++) { -++ char *name = NULL; -++ name = _mk_path(path, dirlist[jj]); -++ free(dirlist[jj]); -++ if (stat(name, &st)) { -++ free(name); -++ continue; -++ } -++ if (!S_ISREG(st.st_mode)) { -++ free(name); -++ continue; -++ } -++ pl = _process_file(name, pl_list, pl_ii); -++ free(name); -++ if (pl != NULL) { -++ pl_list[pl_ii++] = pl; -++ } -++ } -++ free(dirlist); -++ free(path); -++ closedir(dir); -++ dir = NULL; -++ } else { -++ pl = _process_file(argv[ii], pl_list, pl_ii); -++ if (pl != NULL) { -++ pl_list[pl_ii++] = pl; -++ } -++ } -++ } -++ // Cleanup -++ for (ii = 0; ii < pl_ii; ii++) { -++ bd_free_mpls(pl_list[ii]); -++ } -++ return 0; -++} -++ -+diff --git a/src/devtools/util.c b/src/devtools/util.c -+new file mode 100644 -+index 0000000..aaa4c46 -+--- /dev/null -++++ b/src/devtools/util.c -+@@ -0,0 +1,40 @@ -++/* -++ * This file is part of libbluray -++ * Copyright (C) 2009-2010 John Stebbins -++ * -++ * This library is free software; you can redistribute it and/or -++ * modify it under the terms of the GNU Lesser General Public -++ * License as published by the Free Software Foundation; either -++ * version 2.1 of the License, or (at your option) any later version. -++ * -++ * This library is distributed in the hope that it will be useful, -++ * but WITHOUT ANY WARRANTY; without even the implied warranty of -++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -++ * Lesser General Public License for more details. -++ * -++ * You should have received a copy of the GNU Lesser General Public -++ * License along with this library. If not, see -++ * <http://www.gnu.org/licenses/>. -++ */ -++ -++#include <stdio.h> -++#include <stdarg.h> -++ -++#include "util.h" -++ -++void -++indent_printf(int level, const char *fmt, ...) -++{ -++ va_list ap; -++ int ii; -++ -++ for (ii = 0; ii < level; ii++) -++ { -++ printf(" "); -++ } -++ va_start(ap, fmt); -++ vprintf(fmt, ap); -++ va_end(ap); -++ printf("\n"); -++} -++ -+diff --git a/src/devtools/util.h b/src/devtools/util.h -+new file mode 100644 -+index 0000000..144f8ec -+--- /dev/null -++++ b/src/devtools/util.h -+@@ -0,0 +1,43 @@ -++/* -++ * This file is part of libbluray -++ * Copyright (C) 2009-2010 John Stebbins -++ * -++ * This library is free software; you can redistribute it and/or -++ * modify it under the terms of the GNU Lesser General Public -++ * License as published by the Free Software Foundation; either -++ * version 2.1 of the License, or (at your option) any later version. -++ * -++ * This library is distributed in the hope that it will be useful, -++ * but WITHOUT ANY WARRANTY; without even the implied warranty of -++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -++ * Lesser General Public License for more details. -++ * -++ * You should have received a copy of the GNU Lesser General Public -++ * License along with this library. If not, see -++ * <http://www.gnu.org/licenses/>. -++ */ -++ -++#include <stdint.h> -++ -++#include "util/attributes.h" -++ -++#if defined( __MINGW32__ ) -++# undef lseek -++# define lseek _lseeki64 -++# undef fseeko -++# define fseeko fseeko64 -++# undef ftello -++# define ftello ftello64 -++# define flockfile(...) -++# define funlockfile(...) -++# define getc_unlocked getc -++# undef off_t -++# define off_t off64_t -++# undef stat -++# define stat _stati64 -++# define fstat _fstati64 -++# define wstat _wstati64 -++#endif -++ -++void indent_printf(int level, const char *fmt, ...) BD_ATTR_FORMAT_PRINTF(2,3); -++ -+diff --git a/src/examples/bdj_test.c b/src/examples/bdj_test.c -+deleted file mode 100644 -+index d9ebd16..0000000 -++++ /dev/null -+@@ -1,67 +0,0 @@ -+-/* -+- * This file is part of libbluray -+- * Copyright (C) 2010 William Hahne -+- * -+- * This program is free software; you can redistribute it and/or -+- * modify it under the terms of the GNU General Public License -+- * as published by the Free Software Foundation; either version 2 -+- * of the License, or (at your option) any later version. -+- * -+- * This program is distributed in the hope that it will be useful, -+- * but WITHOUT ANY WARRANTY; without even the implied warranty of -+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+- * GNU General Public License for more details. -+- * -+- * You should have received a copy of the GNU General Public License -+- * along with this program. If not, see <http://www.gnu.org/licenses/>. -+- * -+- * In addition, as a special exception, the copyright holders of libbluray -+- * gives permission to link the code of its release of libbluray with the -+- * OpenSSL project's "OpenSSL" library (or with modified versions of it -+- * that use the same license as the "OpenSSL" library), and distribute -+- * the linked executables. You must obey the GNU General Public License -+- * in all respects for all of the code used other than "OpenSSL". If you -+- * modify this file, you may extend this exception to your version of the -+- * file, but you are not obligated to do so. If you do not wish to do -+- * so, delete this exception statement from your version. -+- */ -+- -+-#include <stdio.h> -+-#include <stdlib.h> -+-#include <unistd.h> -+- -+-#include "libbluray/bluray.h" -+- -+-#if defined(_WIN32) -+-#include <windows.h> -+-#define sleep(x) Sleep(x) -+-#endif -+- -+-static void _usage(void) { -+- printf("Usage: [path to disc] [starting object]\n"); -+-} -+- -+-int main(int argc, char** argv) -+-{ -+- if (argc < 3) { -+- _usage(); -+- return 0; -+- } -+- -+- printf("%s %s\n", argv[1], argv[2]); -+- -+- BLURAY* bd = bd_open(argv[1], NULL); -+- -+- bd_get_titles(bd, TITLES_ALL, 0); -+- -+- if (!bd_start_bdj(bd, argv[2])) { -+- printf("Failed to start BD-J application.\n"); -+- } else { -+- while (1) { sleep(20); } -+- bd_stop_bdj(bd); -+- } -+- -+- bd_close(bd); -+- -+- return 0; -+-} -+diff --git a/src/examples/bdjo_dump.c b/src/examples/bdjo_dump.c -+deleted file mode 100644 -+index bcbd2af..0000000 -++++ /dev/null -+@@ -1,206 +0,0 @@ -+-/* -+- * This file is part of libbluray -+- * Copyright (C) 2014 Petri Hintukainen <phintuka@users.sourceforge.net> -+- * -+- * This library is free software; you can redistribute it and/or -+- * modify it under the terms of the GNU Lesser General Public -+- * License as published by the Free Software Foundation; either -+- * version 2.1 of the License, or (at your option) any later version. -+- * -+- * This library is distributed in the hope that it will be useful, -+- * but WITHOUT ANY WARRANTY; without even the implied warranty of -+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+- * Lesser General Public License for more details. -+- * -+- * You should have received a copy of the GNU Lesser General Public -+- * License along with this library. If not, see -+- * <http://www.gnu.org/licenses/>. -+- */ -+- -+-#include "libbluray/bluray.h" -+-#include "libbluray/bdj/bdjo_data.h" -+- -+-#include <stdio.h> -+-#include <string.h> -+- -+-static const char *_yes_no(int i) -+-{ -+- return i > 0 ? "yes" : i < 0 ? "unknown" : "no"; -+-} -+- -+-static const char *_binding_str(int i) -+-{ -+- switch (i) { -+- case 0: return "unbound"; -+- case 1: return "disc bound"; -+- case 3: return "title bound"; -+- default: return "???"; -+- } -+-} -+- -+-static const char *_visibility_str(int i) -+-{ -+- switch (i) { -+- case 0: return "none"; -+- case 1: return "applications"; -+- case 2: return "user"; -+- default: return "???"; -+- } -+-} -+- -+-static void _terminal_info_print(const BDJO_TERMINAL_INFO *p) -+-{ -+- printf("Terminal Info:\n"); -+- printf(" Default AWT font : %s\n", p->default_font); -+- printf(" initial HaVi config : %d\n", p->initial_havi_config_id); -+- printf(" Menu call mask : %d\n", p->menu_call_mask); -+- printf(" Title search mask : %d\n", p->menu_call_mask); -+-} -+- -+-static void _app_cache_item_print(const BDJO_APP_CACHE_ITEM *p) -+-{ -+- printf(" %3.3s: %s%s\n", -+- p->lang_code, p->ref_to_name, -+- p->type == 1 ? ".jar" : p->type == 2 ? "/" : " (unknown type)"); -+-} -+- -+-static void _app_cache_info_print(const BDJO_APP_CACHE_INFO *p) -+-{ -+- unsigned ii; -+- -+- printf("Application cache info:\n"); -+- for (ii = 0; ii < p->num_item; ii++) { -+- _app_cache_item_print(&p->item[ii]); -+- } -+-} -+- -+-static void _accessible_playlists_print(const BDJO_ACCESSIBLE_PLAYLISTS *p) -+-{ -+- unsigned ii; -+- -+- printf("Accessible playlists:\n"); -+- printf(" Access to all : %s\n", _yes_no(p->access_to_all_flag)); -+- printf(" Autostart first : %s\n", _yes_no(p->autostart_first_playlist_flag)); -+- -+- if (p->num_pl) { -+- printf(" Playlists : %d\n", p->num_pl); -+- for (ii = 0; ii < p->num_pl; ii++) { -+- printf(" %s.mpls\n", p->pl[ii].name); -+- } -+- } -+-} -+- -+-static void _app_profile_print(BDJO_APP_PROFILE *p) -+-{ -+- printf(" Profile %d Version %d.%d.%d\n", -+- p->profile_number, p->major_version, p->minor_version, p->micro_version); -+-} -+- -+-static void _app_print(const BDJO_APP *p) -+-{ -+- unsigned ii; -+- -+- printf(" Control code: : %d (%s)\n", p->control_code, -+- p->control_code == 1 ? "autostart" : p->control_code == 2 ? "present" : "???"); -+- printf(" Type : %d (%s)\n", p->type, -+- p->type == 1 ? "BD-J App" : "???"); -+- printf(" Organization ID : %08X\n", p->org_id); -+- printf(" Application ID : %04X\n", p->app_id); -+- printf(" Priority : %d\n", p->priority); -+- printf(" Binding : %d (%s)\n", p->binding, _binding_str(p->binding)); -+- printf(" Visibility : %d (%s)\n", p->visibility, _visibility_str(p->visibility)); -+- -+- if (p->num_profile) { -+- printf(" Profiles:\n"); -+- for (ii = 0; ii < p->num_profile; ii++) { -+- _app_profile_print(&p->profile[ii]); -+- } -+- } -+- -+- if (p->num_name) { -+- printf(" Names:\n"); -+- for (ii = 0; ii < p->num_name; ii++) { -+- printf(" %s: %s\n", p->name[ii].lang, p->name[ii].name); -+- } -+- } -+- -+- printf(" Base directory : %s\n", p->base_dir); -+- printf(" Icon locator : %s\n", p->icon_locator); -+- printf(" Icon flags : 0x%04x\n", p->icon_flags); -+- printf(" Classpath extension : %s\n", p->classpath_extension); -+- printf(" Initial class : %s\n", p->initial_class); -+- printf(" Parameters : "); -+- for (ii = 0; ii < p->num_param; ii++) { -+- printf("%s ", p->param[ii].param); -+- } -+- printf("\n"); -+-} -+- -+-static void _app_management_table_print(const BDJO_APP_MANAGEMENT_TABLE *p) -+-{ -+- unsigned ii; -+- -+- for (ii = 0; ii < p->num_app; ii++) { -+- printf("Application %d:\n", ii); -+- _app_print(&p->app[ii]); -+- } -+-} -+- -+-static void _key_interest_table_print(const BDJO_KEY_INTEREST_TABLE *p) -+-{ -+- unsigned int v; -+- memcpy(&v, p, sizeof(unsigned int)); -+- if (v) { -+- printf("Key interest table:\n"); -+- printf(" %s%s%s%s%s%s%s%s%s%s%s\n", -+- p->vk_play ? "VK_PLAY " : "", -+- p->vk_stop ? "VK_STOP " : "", -+- p->vk_ffw ? "VK_FFW " : "", -+- p->vk_rew ? "VK_REW " : "", -+- p->vk_track_next ? "VK_TRACK_NEXT " : "", -+- p->vk_track_prev ? "VK_TRACK_PREV " : "", -+- p->vk_pause ? "VK_PAUSE " : "", -+- p->vk_still_off ? "VK_STILL_OFF " : "", -+- p->vk_sec_audio_ena_dis ? "VK_SEC_AUDIO " : "", -+- p->vk_sec_video_ena_dis ? "VK_SEC_VIDEO " : "", -+- p->pg_textst_ena_dis ? "VK_PG_TEXTST " : ""); -+- } -+-} -+- -+-static void _file_access_info_print(const BDJO_FILE_ACCESS_INFO *p) -+-{ -+- printf("File access info:\n %s\n", p->path); -+-} -+- -+-static void _bdjo_print(const BDJO *p) -+-{ -+- _terminal_info_print(&p->terminal_info); -+- _app_cache_info_print(&p->app_cache_info); -+- _accessible_playlists_print(&p->accessible_playlists); -+- _app_management_table_print(&p->app_table); -+- _key_interest_table_print(&p->key_interest_table); -+- _file_access_info_print(&p->file_access_info); -+-} -+- -+-int main(int argc, const char *argv[]) -+-{ -+- if (argc < 2) { -+- fprintf(stderr, "usage: %s <bdjo_file>\n", argv[0]); -+- return 1; -+- } -+- -+- int cnt; -+- for (cnt = 1; cnt < argc; cnt++) { -+- -+- printf("%s\n", argv[cnt]); -+- -+- BDJO *bdjo = bd_read_bdjo(argv[cnt]); -+- if (bdjo) { -+- _bdjo_print(bdjo); -+- bd_free_bdjo(bdjo); -+- } -+- printf("\n"); -+- } -+- -+- return 0; -+-} -+diff --git a/src/examples/clpi_dump.c b/src/examples/clpi_dump.c -+deleted file mode 100644 -+index bd64783..0000000 -++++ /dev/null -+@@ -1,487 +0,0 @@ -+-/* -+- * This file is part of libbluray -+- * Copyright (C) 2009-2010 John Stebbins -+- * Copyright (C) 2012-2013 Petri Hintukainen <phintuka@users.sourceforge.net> -+- * -+- * This library is free software; you can redistribute it and/or -+- * modify it under the terms of the GNU Lesser General Public -+- * License as published by the Free Software Foundation; either -+- * version 2.1 of the License, or (at your option) any later version. -+- * -+- * This library is distributed in the hope that it will be useful, -+- * but WITHOUT ANY WARRANTY; without even the implied warranty of -+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+- * Lesser General Public License for more details. -+- * -+- * You should have received a copy of the GNU Lesser General Public -+- * License along with this library. If not, see -+- * <http://www.gnu.org/licenses/>. -+- */ -+- -+-#include <stdio.h> -+-#include <stdlib.h> -+-#include <unistd.h> -+-#include <inttypes.h> -+- -+-#include "libbluray/bdnav/clpi_data.h" -+-#include "libbluray/bluray.h" -+- -+-#include "util.h" -+- -+-static int verbose; -+- -+-typedef struct { -+- int value; -+- const char *str; -+-} VALUE_MAP; -+- -+-static inline const char* -+-_lookup_str(const VALUE_MAP *map, int val) -+-{ -+- int ii; -+- -+- for (ii = 0; map[ii].str; ii++) { -+- if (val == map[ii].value) { -+- return map[ii].str; -+- } -+- } -+- return "?"; -+-} -+- -+-const VALUE_MAP codec_map[] = { -+- {0x01, "MPEG-1 Video"}, -+- {0x02, "MPEG-2 Video"}, -+- {0x03, "MPEG-1 Audio"}, -+- {0x04, "MPEG-2 Audio"}, -+- {0x80, "LPCM"}, -+- {0x81, "AC-3"}, -+- {0x82, "DTS"}, -+- {0x83, "TrueHD"}, -+- {0x84, "AC-3 Plus"}, -+- {0x85, "DTS-HD"}, -+- {0x86, "DTS-HD Master"}, -+- {0xa1, "AC-3 Plus for secondary audio"}, -+- {0xa2, "DTS-HD for secondary audio"}, -+- {0xea, "VC-1"}, -+- {0x1b, "H.264"}, -+- {0x20, "H.264 MVC dep."}, -+- {0x90, "Presentation Graphics"}, -+- {0x91, "Presentation Graphics"}, -+- {0x92, "Interactive Graphics"}, -+- {0, NULL} -+-}; -+- -+-const VALUE_MAP video_format_map[] = { -+- {0, "Reserved"}, -+- {1, "480i"}, -+- {2, "576i"}, -+- {3, "480p"}, -+- {4, "1080i"}, -+- {5, "720p"}, -+- {6, "1080p"}, -+- {7, "576p"}, -+- {0, NULL} -+-}; -+- -+-const VALUE_MAP video_rate_map[] = { -+- {0, "Reserved1"}, -+- {1, "23.976"}, -+- {2, "24"}, -+- {3, "25"}, -+- {4, "29.97"}, -+- {5, "Reserved2"}, -+- {6, "50"}, -+- {7, "59.94"}, -+- {0, NULL} -+-}; -+- -+-const VALUE_MAP video_aspect_map[] = { -+- {0, "Reserved1"}, -+- {1, "Reserved2"}, -+- {2, "4:3"}, -+- {3, "16:9"}, -+- {0, NULL} -+-}; -+- -+-const VALUE_MAP audio_format_map[] = { -+- {0, "Reserved1"}, -+- {1, "Mono"}, -+- {2, "Reserved2"}, -+- {3, "Stereo"}, -+- {4, "Reserved3"}, -+- {5, "Reserved4"}, -+- {6, "Multi Channel"}, -+- {12, "Combo"}, -+- {0, NULL} -+-}; -+- -+-const VALUE_MAP audio_rate_map[] = { -+- {0, "Reserved1"}, -+- {1, "48 Khz"}, -+- {2, "Reserved2"}, -+- {3, "Reserved3"}, -+- {4, "96 Khz"}, -+- {5, "192 Khz"}, -+- {12, "48/192 Khz"}, -+- {14, "48/96 Khz"}, -+- {0, NULL} -+-}; -+- -+-const VALUE_MAP application_type_map[] = { -+- {1, "Main TS for a main-path of Movie"}, -+- {2, "Main TS for a main-path of Time based slide show"}, -+- {3, "Main TS for a main-path of Browsable slide show"}, -+- {4, "Sub TS for a sub-path of Browsable slide show"}, -+- {5, "Sub TS for a sub-path of Interactive Graphics menu"}, -+- {6, "Sub TS for a sub-path of Text subtitle"}, -+- {7, "Sub TS for a sub-path of one or more elementary streams path"}, -+- {0, NULL}, -+-}; -+- -+-static void -+-_show_stream(CLPI_PROG_STREAM *ss, int level) -+-{ -+- indent_printf(level, "Codec (%04x): %s", ss->coding_type, -+- _lookup_str(codec_map, ss->coding_type)); -+- indent_printf(level, "PID: %04x", ss->pid); -+- switch (ss->coding_type) { -+- case 0x01: -+- case 0x02: -+- case 0xea: -+- case 0x1b: -+- case 0x20: -+- indent_printf(level, "Format %02x: %s", ss->format, -+- _lookup_str(video_format_map, ss->format)); -+- indent_printf(level, "Rate %02x: %s", ss->rate, -+- _lookup_str(video_rate_map, ss->rate)); -+- indent_printf(level, "Aspect %02x: %s", ss->aspect, -+- _lookup_str(video_aspect_map, ss->aspect)); -+- indent_printf(level, "oc_flag %02x", ss->oc_flag); -+- break; -+- -+- case 0x03: -+- case 0x04: -+- case 0x80: -+- case 0x81: -+- case 0x82: -+- case 0x83: -+- case 0x84: -+- case 0x85: -+- case 0x86: -+- case 0xa1: -+- case 0xa2: -+- indent_printf(level, "Format %02x: %s", ss->format, -+- _lookup_str(audio_format_map, ss->format)); -+- indent_printf(level, "Rate %02x: %s", ss->rate, -+- _lookup_str(audio_rate_map, ss->rate)); -+- indent_printf(level, "Language: %s", ss->lang); -+- break; -+- -+- case 0x90: -+- case 0x91: -+- case 0xa0: -+- indent_printf(level, "Language: %s", ss->lang); -+- break; -+- -+- case 0x92: -+- indent_printf(level, "Char Code: %02x", ss->char_code); -+- indent_printf(level, "Language: %s", ss->lang); -+- break; -+- -+- default: -+- fprintf(stderr, "unrecognized coding type %02x\n", ss->coding_type); -+- break; -+- }; -+-} -+- -+-static void -+-_show_clip_info(CLPI_CL *cl, int level) -+-{ -+- CLPI_CLIP_INFO *ci = &cl->clip; -+- int ii; -+- -+- indent_printf(level, "Clip Info"); -+- indent_printf(level+1, "Clip Stream Type: %02x", ci->clip_stream_type); -+- indent_printf(level+1, "Clip Application Type (%02x): %s", -+- ci->application_type, _lookup_str(application_type_map, ci->application_type)); -+- indent_printf(level+1, "is_ATC_delta: %s", ci->is_atc_delta ? "True" : "False"); -+- indent_printf(level+1, "ATC delta count: %d", ci->atc_delta_count); -+- indent_printf(level+1, "TS Recording Rate: %u", ci->ts_recording_rate); -+- indent_printf(level+1, "Number Source Packets: %u", ci->num_source_packets); -+- // Show ts type info -+- indent_printf(level+1, "TS Type Info"); -+- indent_printf(level+2, "Validity Flags %02x", ci->ts_type_info.validity); -+- indent_printf(level+2, "Format Id %s", ci->ts_type_info.format_id); -+- // Show cc5 thing -+- for (ii = 0; ii < ci->atc_delta_count; ii++) { -+- indent_printf(level+1, "ATC delta[ %d ]", ii); -+- indent_printf(level+2, "Delta %08x", ci->atc_delta[ii].delta); -+- indent_printf(level+2, "File Id %s", ci->atc_delta[ii].file_id); -+- indent_printf(level+2, "File Code %s", ci->atc_delta[ii].file_code); -+- } -+- // show fonts -+- if (cl->font_info.font_count) { -+- indent_printf(level+1, "Font files"); -+- for (ii = 0; ii < cl->font_info.font_count; ii++) { -+- indent_printf(level+2, "Font file %d: %s.otf", ii+1, cl->font_info.font[ii].file_id); -+- } -+- } -+- -+- printf("\n"); -+-} -+- -+-static void -+-_show_seq_info(CLPI_SEQ_INFO *si, int level) -+-{ -+- CLPI_ATC_SEQ *atc; -+- CLPI_STC_SEQ *stc; -+- int ii, jj; -+- -+- indent_printf(level, "Sequence Info"); -+- indent_printf(level+1, "Number ATC Sequences: %d", si->num_atc_seq); -+- for (ii = 0; ii < si->num_atc_seq; ii++) { -+- atc = &si->atc_seq[ii]; -+- indent_printf(level+1, "ATC Sequence %d", ii); -+- indent_printf(level+2, "SPN ATC Start: %u", atc->spn_atc_start); -+- indent_printf(level+2, "Offset STC Id: %d", atc->offset_stc_id); -+- indent_printf(level+2, "Number STC Sequences: %d", atc->num_stc_seq); -+- for (jj = 0; jj < atc->num_stc_seq; jj++) { -+- stc = &atc->stc_seq[jj]; -+- indent_printf(level+2, "ATC Sequence %d", jj); -+- indent_printf(level+3, "SPN STC Start: %u", stc->spn_stc_start); -+- indent_printf(level+3, "PCR PID: %04x", stc->pcr_pid); -+- indent_printf(level+3, "Presentation Start: %u", -+- stc->presentation_start_time); -+- indent_printf(level+3, "Presentation End: %u", -+- stc->presentation_end_time); -+- } -+- } -+-} -+- -+-static void -+-_show_prog_info(CLPI_PROG_INFO *pi, int level) -+-{ -+- CLPI_PROG *prog; -+- int ii, jj; -+- -+- indent_printf(level, "Program Info"); -+- indent_printf(level+1, "Number Programs: %d", pi->num_prog); -+- for (ii = 0; ii < pi->num_prog; ii++) { -+- prog = &pi->progs[ii]; -+- indent_printf(level+1, "Program %d", ii); -+- indent_printf(level+2, "SPN Program Sequence Start: %d", -+- prog->spn_program_sequence_start); -+- indent_printf(level+2, "Program Map PID: %d", prog->program_map_pid); -+- indent_printf(level+2, "Number Streams: %d", prog->num_streams); -+- indent_printf(level+2, "Number Groups: %d", prog->num_groups); -+- for (jj = 0; jj < prog->num_streams; jj++) { -+- indent_printf(level+2, "Stream %d", jj); -+- _show_stream(&prog->streams[jj], level+3); -+- } -+- } -+-} -+- -+-static void -+-_show_extent_start(CLPI_EXTENT_START *es, int level) -+-{ -+- unsigned int ii; -+- -+- indent_printf(level, "Extension data: Extent Start Point"); -+- -+- if (!es->num_point) { -+- indent_printf(level+1, "(no data)"); -+- -+- } else { -+- indent_printf(level+1, "Number of Start Points: %d", es->num_point); -+- -+- if (verbose) { -+- for (ii = 0; ii < es->num_point; ii++) { -+- indent_printf(level+1, "Extent %5d: SPN 0x%08X", ii, es->point[ii]); -+- } -+- } -+- } -+-} -+- -+-static void -+-_show_cpi_info(CLPI_CPI *cpi, int level) -+-{ -+- CLPI_EP_MAP_ENTRY *entry; -+- CLPI_EP_COARSE *coarse; -+- CLPI_EP_FINE *fine; -+- int ii, jj, kk; -+- -+- indent_printf(level, "CPI"); -+- indent_printf(level+1, "Number Stream PID: %d", cpi->num_stream_pid); -+- for (ii = 0; ii < cpi->num_stream_pid; ii++) { -+- entry = &cpi->entry[ii]; -+- indent_printf(level+1, "Stream: %d", ii); -+- indent_printf(level+2, "PID: %04x", entry->pid); -+- indent_printf(level+2, "EP Stream Type: %d", entry->ep_stream_type); -+- indent_printf(level+2, "Number EP Coarse: %d", entry->num_ep_coarse); -+- indent_printf(level+2, "Number EP Fine: %d", entry->num_ep_fine); -+- indent_printf(level+2, "EP Map Start: %d", -+- entry->ep_map_stream_start_addr); -+- for (jj = 0; jj < entry->num_ep_coarse; jj++) { -+- coarse = &entry->coarse[jj]; -+- indent_printf(level+2, "Coarse: %d", jj); -+- indent_printf(level+3, "Ref EP Fine: %d", coarse->ref_ep_fine_id); -+- indent_printf(level+3, "PTS EP: %d", coarse->pts_ep); -+- indent_printf(level+3, "SPN EP: %d", coarse->spn_ep); -+- } -+- for (jj = 0; jj < entry->num_ep_fine; jj++) { -+- fine = &entry->fine[jj]; -+- indent_printf(level+2, "Fine: %d", jj); -+- indent_printf(level+3, "Angle Change Point: %s", -+- fine->is_angle_change_point ? "True":"False"); -+- indent_printf(level+3, "I End Offset: %d", -+- fine->i_end_position_offset); -+- indent_printf(level+3, "PTS EP: %d", fine->pts_ep); -+- indent_printf(level+3, "SPN EP: %d", fine->spn_ep); -+- } -+- if (verbose) { -+- uint64_t pts; -+- uint32_t spn; -+- -+- indent_printf(level+2, "PTS - SPN Map"); -+- for (jj = 0; jj < entry->num_ep_coarse; jj++) { -+- int start, end; -+- -+- indent_printf(level+3, "Coarse: %d", jj); -+- coarse = &entry->coarse[jj]; -+- start = coarse->ref_ep_fine_id; -+- if (jj < entry->num_ep_coarse - 1) { -+- end = entry->coarse[jj+1].ref_ep_fine_id; -+- } else { -+- end = entry->num_ep_fine; -+- } -+- for (kk = start; kk < end; kk++) { -+- fine = &entry->fine[kk]; -+- pts = ((uint64_t) (coarse->pts_ep & ~0x01) << 19) + -+- ((uint64_t)fine->pts_ep << 9); -+- spn = (coarse->spn_ep & ~0x1FFFF) + fine->spn_ep; -+- indent_printf(level+4, "PTS %8"PRIu64"/%8"PRIu64" -- SPN %u", -+- pts, pts >> 1, spn); -+- } -+- } -+- } -+- } -+-} -+- -+- -+-static void -+-_usage(char *cmd) -+-{ -+- fprintf(stderr, -+-"Usage: %s -vcspi <clpi file> [<clpi file> ...]\n" -+-"With no options, produces no output (not very useful)\n" -+-"Options:\n" -+-" v - Verbose output.\n" -+-" c - Shows the Clip Info structure\n" -+-" s - Shows the Sequence Info structure\n" -+-" p - Shows the Program Info structure\n" -+-" i - Shows the CPI. PTS to SPN map\n" -+-" e - Shows Extent Start Table\n" -+-, cmd); -+- -+- exit(EXIT_FAILURE); -+-} -+- -+-#define OPTS "vcspie" -+- -+-int -+-main(int argc, char *argv[]) -+-{ -+- CLPI_CL *cl; -+- int opt; -+- int opt_clip_info = 0, opt_seq_info = 0, opt_prog_info = 0; -+- int opt_cpi_info = 0, opt_extent_start = 0; -+- int ii; -+- -+- do { -+- opt = getopt(argc, argv, OPTS); -+- switch (opt) { -+- case -1: break; -+- -+- case 'v': -+- verbose = 1; -+- break; -+- -+- case 's': -+- opt_seq_info = 1; -+- break; -+- -+- case 'i': -+- opt_cpi_info = 1; -+- break; -+- -+- case 'c': -+- opt_clip_info = 1; -+- break; -+- -+- case 'p': -+- opt_prog_info = 1; -+- break; -+- -+- case 'e': -+- opt_extent_start = 1; -+- break; -+- -+- default: -+- _usage(argv[0]); -+- break; -+- } -+- } while (opt != -1); -+- -+- if (optind >= argc) { -+- _usage(argv[0]); -+- } -+- -+- for (ii = optind; ii < argc; ii++) { -+- cl = bd_read_clpi(argv[ii]); -+- if (cl == NULL) { -+- fprintf(stderr, "Parsing %s failed\n", argv[ii]); -+- continue; -+- } -+- if (opt_clip_info) { -+- // Show clip info -+- _show_clip_info(cl, 1); -+- } -+- if (opt_seq_info) { -+- // Show sequence info -+- _show_seq_info(&cl->sequence, 1); -+- } -+- if (opt_prog_info) { -+- // Show program info -+- _show_prog_info(&cl->program, 1); -+- } -+- if (opt_cpi_info) { -+- // Show cpi -+- _show_cpi_info(&cl->cpi, 1); -+- } -+- -+- if (opt_prog_info) { -+- if (cl->program_ss.num_prog) { -+- printf("\n"); -+- indent_printf(1, "Extension: Program Info SS"); -+- _show_prog_info(&cl->program_ss, 1); -+- } -+- } -+- if (opt_cpi_info) { -+- if (cl->program_ss.num_prog) { -+- printf("\n"); -+- indent_printf(1, "Extension: CPI SS"); -+- _show_cpi_info(&cl->cpi_ss, 1); -+- } -+- } -+- if (opt_extent_start) { -+- // Show extent start point -+- if (cl->extent_start.num_point > 0) { -+- _show_extent_start(&cl->extent_start, 1); -+- } -+- } -+- -+- bd_free_clpi(cl); -+- } -+- return 0; -+-} -+- -+diff --git a/src/examples/hdmv_test.c b/src/examples/hdmv_test.c -+deleted file mode 100644 -+index 585ed70..0000000 -++++ /dev/null -+@@ -1,257 +0,0 @@ -+-/* -+- * This file is part of libbluray -+- * Copyright (C) 2010 hpi1 -+- * -+- * This library is free software; you can redistribute it and/or -+- * modify it under the terms of the GNU Lesser General Public -+- * License as published by the Free Software Foundation; either -+- * version 2.1 of the License, or (at your option) any later version. -+- * -+- * This library is distributed in the hope that it will be useful, -+- * but WITHOUT ANY WARRANTY; without even the implied warranty of -+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+- * Lesser General Public License for more details. -+- * -+- * You should have received a copy of the GNU Lesser General Public -+- * License along with this library. If not, see -+- * <http://www.gnu.org/licenses/>. -+- */ -+- -+-#include <stdio.h> -+-#include <stdlib.h> -+-#include <string.h> -+-#include <inttypes.h> -+- -+-#include "util/log_control.h" -+-#include "libbluray/bluray.h" -+- -+-static void _print_event(BD_EVENT *ev) -+-{ -+- switch (ev->event) { -+- case BD_EVENT_NONE: -+- break; -+- case BD_EVENT_ERROR: -+- printf("EVENT_ERROR:\t%d\n", ev->param); -+- break; -+- case BD_EVENT_READ_ERROR: -+- printf("EVENT_READ_ERROR:\t%d\n", ev->param); -+- break; -+- case BD_EVENT_ENCRYPTED: -+- printf("EVENT_ENCRYPTED:\t%d\n", ev->param); -+- break; -+- -+- /* current playback position */ -+- -+- case BD_EVENT_ANGLE: -+- printf("EVENT_ANGLE:\t%d\n", ev->param); -+- break; -+- case BD_EVENT_TITLE: -+- printf("EVENT_TITLE:\t%d\n", ev->param); -+- break; -+- case BD_EVENT_PLAYLIST: -+- printf("EVENT_PLAYLIST:\t%d\n", ev->param); -+- break; -+- case BD_EVENT_PLAYITEM: -+- printf("EVENT_PLAYITEM:\t%d\n", ev->param); -+- break; -+- case BD_EVENT_CHAPTER: -+- printf("EVENT_CHAPTER:\t%d\n", ev->param); -+- break; -+- -+- /* */ -+- -+- case BD_EVENT_STILL: -+- printf("EVENT_STILL:\t%d\n", ev->param); -+- break; -+- -+- case BD_EVENT_SEEK: -+- printf("EVENT_SEEK:\t%d\n", ev->param); -+- break; -+- -+- case BD_EVENT_STILL_TIME: -+- if (ev->param) { -+- printf("EVENT_STILL_TIME:\t%d\n", ev->param); -+- } else { -+- printf("EVENT_STILL_TIME:\tinfinite\n"); -+- } -+- break; -+- -+- /* stream selection */ -+- -+- case BD_EVENT_AUDIO_STREAM: -+- printf("EVENT_AUDIO_STREAM:\t%d\n", ev->param); -+- break; -+- case BD_EVENT_IG_STREAM: -+- printf("EVENT_IG_STREAM:\t%d\n", ev->param); -+- break; -+- case BD_EVENT_PG_TEXTST_STREAM: -+- printf("EVENT_PG_TEXTST_STREAM:\t%d\n", ev->param); -+- break; -+- case BD_EVENT_SECONDARY_AUDIO_STREAM: -+- printf("EVENT_SECONDARY_AUDIO_STREAM:\t%d\n", ev->param); -+- break; -+- case BD_EVENT_SECONDARY_VIDEO_STREAM: -+- printf("EVENT_SECONDARY_VIDEO_STREAM:\t%d\n", ev->param); -+- break; -+- -+- case BD_EVENT_PG_TEXTST: -+- printf("EVENT_PG_TEXTST:\t%s\n", ev->param ? "enable" : "disable"); -+- break; -+- case BD_EVENT_SECONDARY_AUDIO: -+- printf("EVENT_SECONDARY_AUDIO:\t%s\n", ev->param ? "enable" : "disable"); -+- break; -+- case BD_EVENT_SECONDARY_VIDEO: -+- printf("EVENT_SECONDARY_VIDEO:\t%s\n", ev->param ? "enable" : "disable"); -+- break; -+- case BD_EVENT_SECONDARY_VIDEO_SIZE: -+- printf("EVENT_SECONDARY_VIDEO_SIZE:\t%s\n", ev->param==0 ? "PIP" : "fullscreen"); -+- break; -+- -+- default: -+- printf("UNKNOWN EVENT %d:\t%d\n", ev->event, ev->param); -+- break; -+- } -+- -+- fflush(stdout); -+-} -+- -+-static void _read_to_eof(BLURAY *bd) -+-{ -+- BD_EVENT ev; -+- int bytes; -+- uint64_t total = 0; -+- uint8_t buf[6144]; -+- -+- bd_seek(bd, bd_get_title_size(bd) - 6144); -+- -+- do { -+- bytes = bd_read_ext(bd, buf, 6144, &ev); -+- total += bytes < 0 ? 0 : bytes; -+- _print_event(&ev); -+- } while (bytes > 0); -+- -+- printf("_read_to_eof(): read %"PRIu64" bytes\n", total); -+-} -+- -+-static void _print_events(BLURAY *bd) -+-{ -+- BD_EVENT ev; -+- -+- do { -+- bd_read_ext(bd, NULL, 0, &ev); -+- _print_event(&ev); -+- } while (ev.event != BD_EVENT_NONE && ev.event != BD_EVENT_ERROR); -+-} -+- -+-static void _play_pl(BLURAY *bd) -+-{ -+- printf("Playing playlist\n"); -+- -+- fflush(stdout); -+- _read_to_eof(bd); -+- -+- printf("Playing playlist done\n\n"); -+- -+- _print_events(bd); -+- -+- printf("\n"); -+-} -+- -+-int main(int argc, char *argv[]) -+-{ -+- int title = -1; -+- int verbose = 0; -+- int args = 0; -+- -+- /* -+- * parse arguments -+- */ -+- -+- if (argc < 2) { -+- printf("\nUsage:\n %s [-v] [-t <title>] <media_path> [<keyfile_path>]\n\n", argv[0]); -+- return -1; -+- } -+- -+- if (!strcmp(argv[1+args], "-v")) { -+- verbose = 1; -+- args++; -+- } -+- -+- if (!strcmp(argv[1+args], "-t")) { -+- args++; -+- title = atoi(argv[1+args]); -+- args++; -+- printf("Requested title %d\n", title); -+- } -+- -+- if (verbose) { -+- printf("Enabling verbose debug\n"); -+- bd_set_debug_mask(bd_get_debug_mask() | DBG_HDMV | DBG_BLURAY); -+- } -+- -+- printf("\n"); -+- -+- /* -+- * open and setup -+- */ -+- -+- BLURAY *bd = bd_open(argv[1+args], argv[2+args]); -+- -+- if (!bd) { -+- printf("bd_open(\'%s\') failed\n", argv[1]); -+- return -1; -+- } -+- -+- bd_set_player_setting (bd, BLURAY_PLAYER_SETTING_PARENTAL, 99); -+- bd_set_player_setting_str(bd, BLURAY_PLAYER_SETTING_AUDIO_LANG, "eng"); -+- bd_set_player_setting_str(bd, BLURAY_PLAYER_SETTING_PG_LANG, "eng"); -+- bd_set_player_setting_str(bd, BLURAY_PLAYER_SETTING_MENU_LANG, "eng"); -+- bd_set_player_setting_str(bd, BLURAY_PLAYER_SETTING_COUNTRY_CODE, NULL); -+- -+- /* -+- * play -+- */ -+- -+- printf("Running first play movie object\n"); -+- -+- fflush(stdout); -+- bd_play(bd); -+- -+- _print_events(bd); -+- -+- printf("\n"); -+- -+- /* -+- * play title -+- */ -+- -+- if (title >= 0) { -+- printf("Playing title %d\n", title); -+- -+- fflush(stdout); -+- bd_play_title(bd, title); -+- -+- _print_events(bd); -+- -+- printf("\n"); -+- } -+- -+- /* -+- * play playlist -+- */ -+- -+- _play_pl(bd); -+- -+- _play_pl(bd); -+- -+- _play_pl(bd); -+- -+- /* -+- * clean up -+- */ -+- -+- bd_close(bd); -+- -+- return 0; -+-} -+- -+diff --git a/src/examples/list_titles.c b/src/examples/list_titles.c -+index 2e0cae8..768f078 100644 -+--- a/src/examples/list_titles.c -++++ b/src/examples/list_titles.c -+@@ -78,7 +78,10 @@ int main(int argc, char *argv[]) -+ _usage(argv[0]); -+ } -+ bd = bd_open(bd_dir, NULL); -+- -++ if (!bd) { -++ fprintf(stderr, "bd_open(%s) failed\n", bd_dir); -++ exit(EXIT_FAILURE); -++ } -+ count = bd_get_titles(bd, flags, seconds); -+ main_title = bd_get_main_title(bd); -+ if (main_title >= 0) { -+@@ -89,7 +92,7 @@ int main(int argc, char *argv[]) -+ BLURAY_TITLE_INFO* ti; -+ ti = bd_get_title_info(bd, ii, 0); -+ printf( -+- "index: %d duration: %02"PRIu64":%02"PRIu64":%02"PRIu64" chapters: %3d angles: %2u clips: %3u (playlist: %05d.mpls) " -++ "index: %3d duration: %02"PRIu64":%02"PRIu64":%02"PRIu64" chapters: %3d angles: %2u clips: %3u (playlist: %05d.mpls) " -+ "V:%d A:%-2d PG:%-2d IG:%-2d SV:%d SA:%d\n", -+ ii + 1, -+ (ti->duration / 90000) / (3600), -+diff --git a/src/examples/mobj_dump.c b/src/examples/mobj_dump.c -+deleted file mode 100644 -+index 3eaf9f4..0000000 -++++ /dev/null -+@@ -1,83 +0,0 @@ -+-/* -+- * This file is part of libbluray -+- * Copyright (C) 2010 hpi1 -+- * -+- * This library is free software; you can redistribute it and/or -+- * modify it under the terms of the GNU Lesser General Public -+- * License as published by the Free Software Foundation; either -+- * version 2.1 of the License, or (at your option) any later version. -+- * -+- * This library is distributed in the hope that it will be useful, -+- * but WITHOUT ANY WARRANTY; without even the implied warranty of -+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+- * Lesser General Public License for more details. -+- * -+- * You should have received a copy of the GNU Lesser General Public -+- * License along with this library. If not, see -+- * <http://www.gnu.org/licenses/>. -+- */ -+- -+-#include "libbluray/bluray.h" -+- -+-#include "libbluray/hdmv/mobj_data.h" -+-#include "libbluray/hdmv/mobj_print.h" -+- -+-#include <stdio.h> -+-#include <string.h> -+- -+-static void _mobj_print(MOBJ_OBJECTS *objects, int disasm) -+-{ -+- int o, c; -+- -+- printf("Number of objects: %d\n", objects->num_objects); -+- -+- for (o = 0; o < objects->num_objects; o++) { -+- -+- printf("Object %d:\n" -+- " number of commands: %d\n" -+- " resume intention flag: %d\n" -+- " menu call mask: %d\n" -+- " title search mask: %d\n", -+- o, objects->objects[o].num_cmds, -+- objects->objects[o].resume_intention_flag, -+- objects->objects[o].menu_call_mask, -+- objects->objects[o].title_search_mask); -+- -+- if (disasm) { -+- printf(" program:\n"); -+- for (c = 0; c < objects->objects[o].num_cmds; c++) { -+- char buf[256]; -+- mobj_sprint_cmd(buf, &objects->objects[o].cmds[c]); -+- printf(" %04d: %s\n", c, buf); -+- } -+- } -+- } -+-} -+- -+-int main(int argc, const char *argv[]) -+-{ -+- int disasm = 0; -+- MOBJ_OBJECTS *mobj = NULL; -+- -+- if (argc < 2) { -+- fprintf(stderr, -+- "usage: %s [-d] <file>\n" -+- "Options:\n" -+- " d disassemble object code\n", -+- argv[0]); -+- return 1; -+- } -+- if (argc > 2) { -+- disasm = !strcmp(argv[1], "-d"); -+- } -+- -+- mobj = bd_read_mobj(argv[argc-1]); -+- -+- if (mobj) { -+- _mobj_print(mobj, disasm); -+- -+- bd_free_mobj(mobj); -+- } -+- -+- return 0; -+-} -+diff --git a/src/examples/mpls_dump.c b/src/examples/mpls_dump.c -+deleted file mode 100644 -+index 619b6b2..0000000 -++++ /dev/null -+@@ -1,797 +0,0 @@ -+-/* -+- * This file is part of libbluray -+- * Copyright (C) 2009-2010 John Stebbins -+- * -+- * This library is free software; you can redistribute it and/or -+- * modify it under the terms of the GNU Lesser General Public -+- * License as published by the Free Software Foundation; either -+- * version 2.1 of the License, or (at your option) any later version. -+- * -+- * This library is distributed in the hope that it will be useful, -+- * but WITHOUT ANY WARRANTY; without even the implied warranty of -+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+- * Lesser General Public License for more details. -+- * -+- * You should have received a copy of the GNU Lesser General Public -+- * License along with this library. If not, see -+- * <http://www.gnu.org/licenses/>. -+- */ -+- -+-#include <sys/stat.h> -+-#include <dirent.h> -+-#include <stdio.h> -+-#include <stdlib.h> -+-#include <unistd.h> -+-#include <string.h> -+-#include <libgen.h> -+- -+-#include "libbluray/bdnav/mpls_parse.h" -+-#include "libbluray/bluray.h" -+- -+-#include "util.h" -+- -+-#ifdef _WIN32 -+-# define DIR_SEP "\\" -+-# define PLAYLIST_DIR "\\BDMV\\PLAYLIST" -+-#else -+-# define DIR_SEP "/" -+-# define PLAYLIST_DIR "/BDMV/PLAYLIST" -+-#endif -+- -+- -+-static int verbose; -+- -+-typedef struct { -+- int value; -+- const char *str; -+-} VALUE_MAP; -+- -+-const VALUE_MAP codec_map[] = { -+- {0x01, "MPEG-1 Video"}, -+- {0x02, "MPEG-2 Video"}, -+- {0x03, "MPEG-1 Audio"}, -+- {0x04, "MPEG-2 Audio"}, -+- {0x80, "LPCM"}, -+- {0x81, "AC-3"}, -+- {0x82, "DTS"}, -+- {0x83, "TrueHD"}, -+- {0x84, "AC-3 Plus"}, -+- {0x85, "DTS-HD"}, -+- {0x86, "DTS-HD Master"}, -+- {0xa1, "AC-3 Plus for secondary audio"}, -+- {0xa2, "DTS-HD for secondary audio"}, -+- {0xea, "VC-1"}, -+- {0x1b, "H.264"}, -+- {0x90, "Presentation Graphics"}, -+- {0x91, "Interactive Graphics"}, -+- {0x92, "Text Subtitle"}, -+- {0, NULL} -+-}; -+- -+-const VALUE_MAP video_format_map[] = { -+- {0, "Reserved"}, -+- {1, "480i"}, -+- {2, "576i"}, -+- {3, "480p"}, -+- {4, "1080i"}, -+- {5, "720p"}, -+- {6, "1080p"}, -+- {7, "576p"}, -+- {0, NULL} -+-}; -+- -+-const VALUE_MAP video_rate_map[] = { -+- {0, "Reserved1"}, -+- {1, "23.976"}, -+- {2, "24"}, -+- {3, "25"}, -+- {4, "29.97"}, -+- {5, "Reserved2"}, -+- {6, "50"}, -+- {7, "59.94"}, -+- {0, NULL} -+-}; -+- -+-const VALUE_MAP audio_format_map[] = { -+- {0, "Reserved1"}, -+- {1, "Mono"}, -+- {2, "Reserved2"}, -+- {3, "Stereo"}, -+- {4, "Reserved3"}, -+- {5, "Reserved4"}, -+- {6, "Multi Channel"}, -+- {12, "Combo"}, -+- {0, NULL} -+-}; -+- -+-const VALUE_MAP audio_rate_map[] = { -+- {0, "Reserved1"}, -+- {1, "48 Khz"}, -+- {2, "Reserved2"}, -+- {3, "Reserved3"}, -+- {4, "96 Khz"}, -+- {5, "192 Khz"}, -+- {12, "48/192 Khz"}, -+- {14, "48/96 Khz"}, -+- {0, NULL} -+-}; -+- -+-const VALUE_MAP subpath_type_map[] = { -+- {2, "Primary audio of the Browsable slideshow"}, -+- {3, "Interactive Graphics presentation menu"}, -+- {4, "Text Subtitle"}, -+- {5, "Out-of-mux Synchronous elementary streams"}, -+- {6, "Out-of-mux Asynchronous Picture-in-Picture presentation"}, -+- {7, "In-mux Synchronous Picture-in-Picture presentation"}, -+- {8, "SS Video"}, -+- {0,NULL} -+-}; -+- -+-const VALUE_MAP playback_type_map[] = { -+- {1, "Sequential"}, -+- {2, "Random"}, -+- {3, "Shuffle"}, -+- {0, NULL} -+-}; -+- -+-const VALUE_MAP connection_type_map[] = { -+- {1, "Non-seamless"}, -+- {5, "Seamless"}, -+- {6, "Seamless"}, -+- {0, NULL} -+-}; -+- -+-static const char* -+-_lookup_str(const VALUE_MAP *map, int val) -+-{ -+- int ii; -+- -+- for (ii = 0; map[ii].str; ii++) { -+- if (val == map[ii].value) { -+- return map[ii].str; -+- } -+- } -+- return "?"; -+-} -+- -+-static char * -+-_mk_path(const char *base, const char *sub) -+-{ -+- size_t n1 = strlen(base); -+- size_t n2 = strlen(sub); -+- char *result = (char*)malloc(n1 + n2 + strlen(DIR_SEP) + 1); -+- strcpy(result, base); -+- strcat(result, DIR_SEP); -+- strcat(result, sub); -+- -+- return result; -+-} -+- -+-static void -+-_show_stream(MPLS_STREAM *ss, int level) -+-{ -+- indent_printf(level, "Codec (%04x): %s", ss->coding_type, -+- _lookup_str(codec_map, ss->coding_type)); -+- switch (ss->stream_type) { -+- case 1: -+- indent_printf(level, "PID: %04x", ss->pid); -+- break; -+- -+- case 2: -+- case 4: -+- indent_printf(level, "SubPath Id: %02x", ss->subpath_id); -+- indent_printf(level, "SubClip Id: %02x", ss->subclip_id); -+- indent_printf(level, "PID: %04x", ss->pid); -+- break; -+- -+- case 3: -+- indent_printf(level, "SubPath Id: %02x", ss->subpath_id); -+- indent_printf(level, "PID: %04x", ss->pid); -+- break; -+- -+- default: -+- fprintf(stderr, "unrecognized stream type %02x\n", ss->stream_type); -+- break; -+- }; -+- -+- switch (ss->coding_type) { -+- case 0x01: -+- case 0x02: -+- case 0xea: -+- case 0x1b: -+- indent_printf(level, "Format %02x: %s", ss->format, -+- _lookup_str(video_format_map, ss->format)); -+- indent_printf(level, "Rate %02x: %s", ss->rate, -+- _lookup_str(video_rate_map, ss->rate)); -+- break; -+- -+- case 0x03: -+- case 0x04: -+- case 0x80: -+- case 0x81: -+- case 0x82: -+- case 0x83: -+- case 0x84: -+- case 0x85: -+- case 0x86: -+- case 0xa1: -+- case 0xa2: -+- indent_printf(level, "Format %02x: %s", ss->format, -+- _lookup_str(audio_format_map, ss->format)); -+- indent_printf(level, "Rate %02x: %s", ss->rate, -+- _lookup_str(audio_rate_map, ss->rate)); -+- indent_printf(level, "Language: %s", ss->lang); -+- break; -+- -+- case 0x90: -+- case 0x91: -+- indent_printf(level, "Language: %s", ss->lang); -+- break; -+- -+- case 0x92: -+- indent_printf(level, "Char Code: %02x", ss->char_code); -+- indent_printf(level, "Language: %s", ss->lang); -+- break; -+- -+- default: -+- fprintf(stderr, "unrecognized coding type %02x\n", ss->coding_type); -+- break; -+- }; -+-} -+- -+-static void -+-_show_details(MPLS_PL *pl, int level) -+-{ -+- int ii, jj, kk; -+- -+- for (ii = 0; ii < pl->list_count; ii++) { -+- MPLS_PI *pi; -+- -+- pi = &pl->play_item[ii]; -+- indent_printf(level, "Clip Id %s", pi->clip[0].clip_id); -+- indent_printf(level+1, "Stc Id: %02x", pi->clip[0].stc_id); -+- indent_printf(level+1, "Connection Condition: %s (%02x)", -+- _lookup_str(connection_type_map, pi->connection_condition), -+- pi->connection_condition); -+- indent_printf(level+1, "In-Time: %d", pi->in_time); -+- indent_printf(level+1, "Out-Time: %d", pi->out_time); -+- if (pi->still_mode == 1) { -+- indent_printf(level+1, "Still time: %ds\n", pi->still_time); -+- } -+- if (pi->still_mode == 2) { -+- indent_printf(level+1, "Still time: infinite\n"); -+- } -+- if (pi->angle_count > 1) { -+- for (jj = 1; jj < pi->angle_count; jj++) { -+- indent_printf(level+1, "Angle %d:", jj); -+- indent_printf(level+2, "Clip Id %s", pi->clip[jj].clip_id); -+- indent_printf(level+2, "Stc Id: %02x", pi->clip[jj].stc_id); -+- } -+- } -+- for (jj = 0; jj < pi->stn.num_video; jj++) { -+- indent_printf(level+1, "Video Stream %d:", jj); -+- _show_stream(&pi->stn.video[jj], level + 2); -+- } -+- for (jj = 0; jj < pi->stn.num_audio; jj++) { -+- indent_printf(level+1, "Audio Stream %d:", jj); -+- _show_stream(&pi->stn.audio[jj], level + 2); -+- } -+- for (jj = 0; jj < pi->stn.num_ig; jj++) { -+- indent_printf(level+1, "Interactive Graphics Stream %d:", jj); -+- _show_stream(&pi->stn.ig[jj], level + 2); -+- } -+- for (jj = 0; jj < (pi->stn.num_pg + pi->stn.num_pip_pg); jj++) { -+- if (jj < pi->stn.num_pg) { -+- indent_printf(level+1, "Presentation Graphics Stream %d:", jj); -+- } else { -+- indent_printf(level+1, "PIP Presentation Graphics Stream %d:", jj); -+- } -+- _show_stream(&pi->stn.pg[jj], level + 2); -+- } -+- for (jj = 0; jj < pi->stn.num_secondary_video; jj++) { -+- indent_printf(level+1, "Secondary Video Stream %d:", jj); -+- _show_stream(&pi->stn.secondary_video[jj], level + 2); -+- for (kk = 0; kk < pi->stn.secondary_video[jj].sv_num_secondary_audio_ref; kk++) { -+- indent_printf(level+2, "Secondary Audio Ref %d: %d", kk,pi->stn.secondary_video[jj].sv_secondary_audio_ref[kk]); -+- } -+- for (kk = 0; kk < pi->stn.secondary_video[jj].sv_num_pip_pg_ref; kk++) { -+- indent_printf(level+2, "PIP Presentation Graphic Ref %d: %d", kk,pi->stn.secondary_video[jj].sv_pip_pg_ref[kk]); -+- } -+- } -+- for (jj = 0; jj < pi->stn.num_secondary_audio; jj++) { -+- indent_printf(level+1, "Secondary Audio Stream %d:", jj); -+- _show_stream(&pi->stn.secondary_audio[jj], level + 2); -+- for (kk = 0; kk < pi->stn.secondary_audio[jj].sa_num_primary_audio_ref; kk++) { -+- indent_printf(level+2, "Primary Audio Ref %d: %d", kk,pi->stn.secondary_audio[jj].sa_primary_audio_ref[kk]); -+- } -+- } -+- printf("\n"); -+- } -+-} -+- -+-static void -+-_show_ai(MPLS_PL *pl, int level) -+-{ -+- indent_printf(level, "Playback type: %s (%d)", -+- _lookup_str(playback_type_map, pl->app_info.playback_type), -+- pl->app_info.playback_type); -+- if (pl->app_info.playback_type == 2 || pl->app_info.playback_type == 3) { -+- indent_printf(level+1, "Playback count: %d", pl->app_info.playback_count); -+- } -+-} -+- -+-static void -+-_show_marks(MPLS_PL *pl, int level) -+-{ -+- int ii; -+- -+- indent_printf(level, "PlayMark Count %d", pl->mark_count); -+- for (ii = 0; ii < pl->mark_count; ii++) { -+- MPLS_PI *pi; -+- MPLS_PLM *plm; -+- int min; -+- double sec; -+- -+- plm = &pl->play_mark[ii]; -+- indent_printf(level, "PlayMark %d", ii); -+- indent_printf(level+1, "Type: %02x", plm->mark_type); -+- if (plm->play_item_ref < pl->list_count) { -+- pi = &pl->play_item[plm->play_item_ref]; -+- indent_printf(level+1, "PlayItem: %s", pi->clip[0].clip_id); -+- } else { -+- indent_printf(level+1, "PlayItem: Invalid reference"); -+- } -+- indent_printf(level+1, "Time (ticks): %u", plm->time); -+- min = plm->duration / (45000*60); -+- sec = (double)(plm->duration - min * 45000 * 60) / 45000; -+- indent_printf(level+1, "Duration (mm:ss.ms, ticks): %d:%.2f, %u", -+- min, sec, plm->duration); -+- printf("\n"); -+- } -+-} -+- -+-static void -+-_show_clip_list(MPLS_PL *pl, int level) -+-{ -+- int ii, jj; -+- -+- for (ii = 0; ii < pl->list_count; ii++) { -+- MPLS_PI *pi; -+- -+- pi = &pl->play_item[ii]; -+- if (verbose) { -+- uint32_t duration; -+- -+- duration = pi->out_time - pi->in_time; -+- indent_printf(level, "%s.m2ts -- Duration: %3d:%02d", -+- pi->clip[0].clip_id, -+- duration / (45000 * 60), (duration / 45000) % 60); -+- } else { -+- indent_printf(level, "%s.m2ts", pi->clip[0].clip_id); -+- } -+- if (pi->angle_count > 1) { -+- for (jj = 1; jj < pi->angle_count; jj++) { -+- indent_printf(level+1, "Angle %d: %s.m2ts", jj+1, pi->clip[jj].clip_id); -+- } -+- } -+- } -+- printf("\n"); -+-} -+- -+-static void -+-_show_sub_path(MPLS_SUB *sub, int level) -+-{ -+- int ii; -+- -+- indent_printf(level+1, "Type: %d (%s)", sub->type, _lookup_str(subpath_type_map, sub->type)); -+- indent_printf(level+1, "Repeat: %d", sub->is_repeat); -+- indent_printf(level+1, "Sub playitem count: %d", sub->sub_playitem_count); -+- -+- for (ii = 0; ii < sub->sub_playitem_count; ii++) { -+- MPLS_SUB_PI *pi; -+- -+- pi = &sub->sub_play_item[ii]; -+- -+- if (verbose) { -+- indent_printf(level+1, "Sub playitem %d", ii); -+- indent_printf(level+2, "Clip Id %s", pi->clip[0].clip_id); -+- indent_printf(level+2, "Multi clip: %d", pi->is_multi_clip); -+- indent_printf(level+2, "Clip count: %d", pi->clip_count); -+- indent_printf(level+2, "Connection Condition: %s (%02x)", -+- _lookup_str(connection_type_map, pi->connection_condition), -+- pi->connection_condition); -+- indent_printf(level+2, "In-Time: %d", pi->in_time); -+- indent_printf(level+2, "Out-Time: %d", pi->out_time); -+- indent_printf(level+2, "Sync playitem Id: %d", pi->sync_play_item_id); -+- indent_printf(level+2, "Sync PTS: %d", pi->sync_pts); -+- } else { -+- indent_printf(level+1, "%s.m2ts", pi->clip[0].clip_id); -+- } -+- } -+-} -+- -+-static void -+-_show_pip_metadata_block(MPLS_PIP_METADATA *block, int level) -+-{ -+- int ii; -+- -+- indent_printf(level, "Clip ref: %d", block->clip_ref); -+- indent_printf(level, "Secondary video ref: %d", block->secondary_video_ref); -+- indent_printf(level, "Timeline type: %d", block->timeline_type); -+- indent_printf(level, "Luma key flag: %d", block->luma_key_flag); -+- if (block->luma_key_flag) { -+- indent_printf(level, "Upper limit luma key: %d", block->upper_limit_luma_key); -+- } -+- indent_printf(level, "Trick play flag: %d", block->trick_play_flag); -+- -+- for (ii = 0; ii < block->data_count; ii++) { -+- indent_printf(level, "data block %d:", ii); -+- indent_printf(level+1, "Timestamp: %d", block->data[ii].time); -+- indent_printf(level+1, "Horizontal position %d", block->data[ii].xpos); -+- indent_printf(level+1, "Vertical position: %d", block->data[ii].ypos); -+- indent_printf(level+1, "Scaling factor: %d", block->data[ii].scale_factor); -+- } -+-} -+- -+-static void -+-_show_pip_metadata(MPLS_PL *pl, int level) -+-{ -+- int ii; -+- -+- for (ii = 0; ii < pl->ext_pip_data_count; ii++) { -+- MPLS_PIP_METADATA *data; -+- -+- data = &pl->ext_pip_data[ii]; -+- -+- indent_printf(level, "PiP metadata block %d:", ii); -+- _show_pip_metadata_block(data, level+1); -+- } -+-} -+- -+-static void -+-_show_sub_paths(MPLS_PL *pl, int level) -+-{ -+- int ss; -+- -+- for (ss = 0; ss < pl->sub_count; ss++) { -+- MPLS_SUB *sub; -+- -+- sub = &pl->sub_path[ss]; -+- -+- indent_printf(level, "Sub Path %d:", ss); -+- _show_sub_path(sub, level+1); -+- } -+-} -+- -+-static void -+-_show_sub_paths_ss(MPLS_PL *pl, int level) -+-{ -+- int ss; -+- -+- for (ss = 0; ss < pl->ext_sub_count; ss++) { -+- MPLS_SUB *sub; -+- -+- sub = &pl->ext_sub_path[ss]; -+- -+- indent_printf(level, "Extension Sub Path %d:", ss); -+- _show_sub_path(sub, level+1); -+- } -+-} -+- -+-static uint32_t -+-_pl_duration(MPLS_PL *pl) -+-{ -+- int ii; -+- uint32_t duration = 0; -+- MPLS_PI *pi; -+- -+- for (ii = 0; ii < pl->list_count; ii++) { -+- pi = &pl->play_item[ii]; -+- duration += pi->out_time - pi->in_time; -+- } -+- return duration; -+-} -+- -+-static int -+-_filter_dup(MPLS_PL *pl_list[], int count, MPLS_PL *pl) -+-{ -+- int ii, jj; -+- -+- for (ii = 0; ii < count; ii++) { -+- if (pl->list_count != pl_list[ii]->list_count || -+- _pl_duration(pl) != _pl_duration(pl_list[ii])) { -+- continue; -+- } -+- for (jj = 0; jj < pl->list_count; jj++) { -+- MPLS_PI *pi1, *pi2; -+- -+- pi1 = &pl->play_item[jj]; -+- pi2 = &pl_list[ii]->play_item[jj]; -+- -+- if (memcmp(pi1->clip[0].clip_id, pi2->clip[0].clip_id, 5) != 0 || -+- pi1->in_time != pi2->in_time || -+- pi1->out_time != pi2->out_time) { -+- break; -+- } -+- } -+- if (jj != pl->list_count) { -+- continue; -+- } -+- return 0; -+- } -+- return 1; -+-} -+- -+-static int -+-_find_repeats(MPLS_PL *pl, const char *m2ts) -+-{ -+- int ii, count = 0; -+- -+- for (ii = 0; ii < pl->list_count; ii++) { -+- MPLS_PI *pi; -+- -+- pi = &pl->play_item[ii]; -+- // Ignore titles with repeated segments -+- if (strcmp(pi->clip[0].clip_id, m2ts) == 0) { -+- count++; -+- } -+- } -+- return count; -+-} -+- -+-static int -+-_filter_short(MPLS_PL *pl, unsigned int seconds) -+-{ -+- // Ignore short playlists -+- if (_pl_duration(pl) / 45000 <= seconds) { -+- return 0; -+- } -+- return 1; -+-} -+- -+-static int -+-_filter_repeats(MPLS_PL *pl, int repeats) -+-{ -+- int ii; -+- -+- for (ii = 0; ii < pl->list_count; ii++) { -+- MPLS_PI *pi; -+- -+- pi = &pl->play_item[ii]; -+- // Ignore titles with repeated segments -+- if (_find_repeats(pl, pi->clip[0].clip_id) > repeats) { -+- return 0; -+- } -+- } -+- return 1; -+-} -+- -+-static int clip_list = 0, playlist_info = 0, chapter_marks = 0, sub_paths = 0, pip_metadata = 0; -+-static int repeats = 0, seconds = 0, dups = 0; -+- -+-static MPLS_PL* -+-_process_file(char *name, MPLS_PL *pl_list[], int pl_count) -+-{ -+- MPLS_PL *pl; -+- -+- pl = bd_read_mpls(name); -+- if (pl == NULL) { -+- fprintf(stderr, "Parse failed: %s\n", name); -+- return NULL; -+- } -+- if (seconds) { -+- if (!_filter_short(pl, seconds)) { -+- bd_free_mpls(pl); -+- return NULL; -+- } -+- } -+- if (repeats) { -+- if (!_filter_repeats(pl, repeats)) { -+- bd_free_mpls(pl); -+- return NULL; -+- } -+- } -+- if (dups) { -+- if (!_filter_dup(pl_list, pl_count, pl)) { -+- bd_free_mpls(pl); -+- return NULL; -+- } -+- } -+- if (verbose) { -+- indent_printf(0, -+- "%s -- Num Clips: %3d , Duration: minutes %4u:%02u", -+- basename(name), -+- pl->list_count, -+- _pl_duration(pl) / (45000 * 60), -+- (_pl_duration(pl) / 45000) % 60); -+- _show_ai(pl, 1); -+- } else { -+- indent_printf(0, "%s -- Duration: minutes %4u:%02u", -+- basename(name), -+- _pl_duration(pl) / (45000 * 60), -+- (_pl_duration(pl) / 45000) % 60); -+- } -+- if (playlist_info) { -+- _show_details(pl, 1); -+- } -+- if (chapter_marks) { -+- _show_marks(pl, 1); -+- } -+- if (pip_metadata) { -+- _show_pip_metadata(pl, 1); -+- } -+- if (clip_list) { -+- _show_clip_list(pl, 1); -+- } -+- if (sub_paths) { -+- _show_sub_paths(pl, 1); -+- _show_sub_paths_ss(pl, 1); -+- } -+- return pl; -+-} -+- -+-static void -+-_usage(char *cmd) -+-{ -+- fprintf(stderr, -+-"Usage: %s -vli <mpls file> [<mpls file> ...]\n" -+-"With no options, produces a list of the playlist(s) with durations\n" -+-"Options:\n" -+-" v - Verbose output.\n" -+-" l - Produces a list of the m2ts clips\n" -+-" i - Dumps detailed information about each clip\n" -+-" c - Show chapter marks\n" -+-" p - Show sub paths\n" -+-" P - Show picture-in-picture metadata\n" -+-" r <N> - Filter out titles that have >N repeating clips\n" -+-" d - Filter out duplicate titles\n" -+-" s <seconds> - Filter out short titles\n" -+-" f - Filter combination -r2 -d -s900\n" -+-, cmd); -+- -+- exit(EXIT_FAILURE); -+-} -+- -+-#define OPTS "vlicpPfr:ds:" -+- -+-static int -+-_qsort_str_cmp(const void *a, const void *b) -+-{ -+- const char *stra = *(char * const *)a; -+- const char *strb = *(char * const *)b; -+- -+- return strcmp(stra, strb); -+-} -+- -+-int -+-main(int argc, char *argv[]) -+-{ -+- MPLS_PL *pl; -+- int opt; -+- int ii, pl_ii; -+- MPLS_PL *pl_list[1000]; -+- struct stat st; -+- char *path = NULL; -+- DIR *dir = NULL; -+- -+- do { -+- opt = getopt(argc, argv, OPTS); -+- switch (opt) { -+- case -1: -+- break; -+- -+- case 'v': -+- verbose = 1; -+- break; -+- -+- case 'l': -+- clip_list = 1; -+- break; -+- -+- case 'i': -+- playlist_info = 1; -+- break; -+- -+- case 'c': -+- chapter_marks = 1; -+- break; -+- -+- case 'p': -+- sub_paths = 1; -+- break; -+- -+- case 'P': -+- pip_metadata = 1; -+- break; -+- -+- case 'd': -+- dups = 1; -+- break; -+- -+- case 'r': -+- repeats = atoi(optarg); -+- break; -+- -+- case 'f': -+- repeats = 2; -+- dups = 1; -+- seconds = 900; -+- break; -+- -+- case 's': -+- seconds = atoi(optarg); -+- break; -+- -+- default: -+- _usage(argv[0]); -+- break; -+- } -+- } while (opt != -1); -+- -+- if (optind >= argc) { -+- _usage(argv[0]); -+- } -+- -+- for (pl_ii = 0, ii = optind; pl_ii < 1000 && ii < argc; ii++) { -+- -+- if (stat(argv[ii], &st)) { -+- continue; -+- } -+- dir = NULL; -+- if (S_ISDIR(st.st_mode)) { -+- -+- printf("Directory: %s:\n", argv[ii]); -+- path = _mk_path(argv[ii], PLAYLIST_DIR); -+- if (path == NULL) { -+- fprintf(stderr, "Failed to find playlist path: %s\n", argv[ii]); -+- continue; -+- } -+- dir = opendir(path); -+- if (dir == NULL) { -+- fprintf(stderr, "Failed to open dir: %s\n", path); -+- free(path); -+- continue; -+- } -+- } -+- if (dir != NULL) { -+- char **dirlist = (char**)calloc(10001, sizeof(char*)); -+- struct dirent *ent; -+- int jj = 0; -+- for (ent = readdir(dir); ent != NULL; ent = readdir(dir)) { -+- dirlist[jj++] = strcpy((char*)malloc(strlen(ent->d_name)), ent->d_name); -+- } -+- qsort(dirlist, jj, sizeof(char*), _qsort_str_cmp); -+- for (jj = 0; dirlist[jj] != NULL; jj++) { -+- char *name = NULL; -+- name = _mk_path(path, dirlist[jj]); -+- free(dirlist[jj]); -+- if (stat(name, &st)) { -+- free(name); -+- continue; -+- } -+- if (!S_ISREG(st.st_mode)) { -+- free(name); -+- continue; -+- } -+- pl = _process_file(name, pl_list, pl_ii); -+- free(name); -+- if (pl != NULL) { -+- pl_list[pl_ii++] = pl; -+- } -+- } -+- free(dirlist); -+- free(path); -+- } else { -+- pl = _process_file(argv[ii], pl_list, pl_ii); -+- if (pl != NULL) { -+- pl_list[pl_ii++] = pl; -+- } -+- } -+- } -+- // Cleanup -+- for (ii = 0; ii < pl_ii; ii++) { -+- bd_free_mpls(pl_list[ii]); -+- } -+- return 0; -+-} -+- -+diff --git a/src/examples/util.c b/src/examples/util.c -+deleted file mode 100644 -+index aaa4c46..0000000 -++++ /dev/null -+@@ -1,40 +0,0 @@ -+-/* -+- * This file is part of libbluray -+- * Copyright (C) 2009-2010 John Stebbins -+- * -+- * This library is free software; you can redistribute it and/or -+- * modify it under the terms of the GNU Lesser General Public -+- * License as published by the Free Software Foundation; either -+- * version 2.1 of the License, or (at your option) any later version. -+- * -+- * This library is distributed in the hope that it will be useful, -+- * but WITHOUT ANY WARRANTY; without even the implied warranty of -+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+- * Lesser General Public License for more details. -+- * -+- * You should have received a copy of the GNU Lesser General Public -+- * License along with this library. If not, see -+- * <http://www.gnu.org/licenses/>. -+- */ -+- -+-#include <stdio.h> -+-#include <stdarg.h> -+- -+-#include "util.h" -+- -+-void -+-indent_printf(int level, const char *fmt, ...) -+-{ -+- va_list ap; -+- int ii; -+- -+- for (ii = 0; ii < level; ii++) -+- { -+- printf(" "); -+- } -+- va_start(ap, fmt); -+- vprintf(fmt, ap); -+- va_end(ap); -+- printf("\n"); -+-} -+- -+diff --git a/src/examples/util.h b/src/examples/util.h -+deleted file mode 100644 -+index 144f8ec..0000000 -++++ /dev/null -+@@ -1,43 +0,0 @@ -+-/* -+- * This file is part of libbluray -+- * Copyright (C) 2009-2010 John Stebbins -+- * -+- * This library is free software; you can redistribute it and/or -+- * modify it under the terms of the GNU Lesser General Public -+- * License as published by the Free Software Foundation; either -+- * version 2.1 of the License, or (at your option) any later version. -+- * -+- * This library is distributed in the hope that it will be useful, -+- * but WITHOUT ANY WARRANTY; without even the implied warranty of -+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+- * Lesser General Public License for more details. -+- * -+- * You should have received a copy of the GNU Lesser General Public -+- * License along with this library. If not, see -+- * <http://www.gnu.org/licenses/>. -+- */ -+- -+-#include <stdint.h> -+- -+-#include "util/attributes.h" -+- -+-#if defined( __MINGW32__ ) -+-# undef lseek -+-# define lseek _lseeki64 -+-# undef fseeko -+-# define fseeko fseeko64 -+-# undef ftello -+-# define ftello ftello64 -+-# define flockfile(...) -+-# define funlockfile(...) -+-# define getc_unlocked getc -+-# undef off_t -+-# define off_t off64_t -+-# undef stat -+-# define stat _stati64 -+-# define fstat _fstati64 -+-# define wstat _wstati64 -+-#endif -+- -+-void indent_printf(int level, const char *fmt, ...) BD_ATTR_FORMAT_PRINTF(2,3); -+- +diff --git a/src/file/dir_win32.c b/src/file/dir_win32.c +index 2690658..f42114d 100644 +--- a/src/file/dir_win32.c @@ -74554,32 +50832,19 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + else + priv->handle = -1; +diff --git a/src/file/dirs_win32.c b/src/file/dirs_win32.c -+index 5279ea5..3d07251 100644 ++index e165fea..3d07251 100644 +--- a/src/file/dirs_win32.c ++++ b/src/file/dirs_win32.c -+@@ -36,10 +36,18 @@ ++@@ -36,7 +36,7 @@ + + char *win32_get_font_dir(const char *font_file) + { +- wchar_t wdir[MAX_PATH]; ++ wchar_t wdir[MAX_PATH+1] = {0}; + if (S_OK != SHGetFolderPathW(NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, wdir)) { -+- GetWindowsDirectoryW(wdir, MAX_PATH); -+- wcscat(wdir, L"\\fonts"); -++ int lenght = GetWindowsDirectoryW(wdir, MAX_PATH); -++ if (lenght == 0 || lenght > (MAX_PATH - 8)) { -++ BD_DEBUG(DBG_FILE, "Font directory path too long!\n"); -++ return NULL; -++ } -++ if (!wcscat(wdir, L"\\fonts")) { -++ BD_DEBUG(DBG_FILE, "Could not construct font directory path!\n"); -++ return NULL; -++ } -++ -+ } -+ -+ int len = WideCharToMultiByte (CP_UTF8, 0, wdir, -1, NULL, 0, NULL, NULL); -+@@ -59,7 +67,7 @@ char *file_get_config_home(void) ++ int lenght = GetWindowsDirectoryW(wdir, MAX_PATH); ++ if (lenght == 0 || lenght > (MAX_PATH - 8)) { ++@@ -67,7 +67,7 @@ char *file_get_config_home(void) + + char *file_get_data_home(void) + { @@ -74588,7 +50853,7 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + + /* Get the "Application Data" folder for the user */ + if (S_OK == SHGetFolderPathW(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, -+@@ -84,7 +92,7 @@ char *file_get_cache_home(void) ++@@ -92,7 +92,7 @@ char *file_get_cache_home(void) + const char *file_get_config_system(const char *dir) + { + static char *appdir = NULL; @@ -74619,44 +50884,11 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + HMODULE hModule; + wchar_t wpath[MAX_PATH]; + -+diff --git a/src/file/file.c b/src/file/file.c -+index 15edfe0..2f85248 100644 -+--- a/src/file/file.c -++++ b/src/file/file.c -+@@ -52,6 +52,10 @@ int file_mkdirs(const char *path) -+ char *end = dir; -+ char *p; -+ -++ if (!dir) { -++ return -1; -++ } -++ -+ /* strip file name */ -+ if (!(end = strrchr(end, DIR_SEP_CHAR))) { -+ X_FREE(dir); -+diff --git a/src/file/file_posix.c b/src/file/file_posix.c -+index 753a8ce..2a79f6f 100644 -+--- a/src/file/file_posix.c -++++ b/src/file/file_posix.c -+@@ -38,6 +38,13 @@ -+ #include <sys/stat.h> -+ #include <fcntl.h> -+ -++#ifdef __ANDROID__ -++# undef lseek -++# define lseek lseek64 -++# undef off_t -++# define off_t off64_t -++#endif -++ -+ static void _file_close(BD_FILE_H *file) -+ { -+ if (file) { +diff --git a/src/file/file_win32.c b/src/file/file_win32.c -+index 5eb52d7..c0f48e4 100644 ++index d9845fb..b4fb7ad 100644 +--- a/src/file/file_win32.c ++++ b/src/file/file_win32.c -+@@ -97,9 +97,9 @@ static BD_FILE_H *_file_open(const char* filename, const char *mode) ++@@ -107,9 +107,9 @@ static BD_FILE_H *_file_open(const char* filename, const char *mode) + { + BD_FILE_H *file; + FILE *fp; @@ -74668,7 +50900,7 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + !MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, mode, -1, wmode, 8)) { + + BD_DEBUG(DBG_FILE, "Error opening file %s\n", filename); -+@@ -112,6 +112,9 @@ static BD_FILE_H *_file_open(const char* filename, const char *mode) ++@@ -122,6 +122,9 @@ static BD_FILE_H *_file_open(const char* filename, const char *mode) + return NULL; + } + @@ -74678,2210 +50910,8 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + file = calloc(1, sizeof(BD_FILE_H)); + if (!file) { + BD_DEBUG(DBG_FILE | DBG_CRIT, "Error opening file %s (out of memory)\n", filename); -+diff --git a/src/file/mount.c b/src/file/mount.c -+index 6382d8b..7575f89 100644 -+--- a/src/file/mount.c -++++ b/src/file/mount.c -+@@ -33,6 +33,7 @@ -+ -+ char *mount_get_mountpoint(const char *device_path) -+ { -++#ifndef __ANDROID__ -+ #ifdef HAVE_MNTENT_H -+ struct stat st; -+ if (stat (device_path, &st) ) { -+@@ -62,6 +63,7 @@ char *mount_get_mountpoint(const char *device_path) -+ endmntent (f); -+ } -+ #endif /* HAVE_MNTENT_H */ -++#endif /* __ANDROID__ */ -+ -+ return str_dup(device_path); -+ } -+diff --git a/src/libbluray/bdj/bdj.c b/src/libbluray/bdj/bdj.c -+index 3465c69..23d944a 100644 -+--- a/src/libbluray/bdj/bdj.c -++++ b/src/libbluray/bdj/bdj.c -+@@ -26,6 +26,7 @@ -+ -+ #include "native/register_native.h" -+ -++#include "file/file.h" -+ #include "file/dirs.h" -+ #include "file/dl.h" -+ #include "util/strutl.h" -+@@ -41,9 +42,6 @@ -+ #ifdef _WIN32 -+ #include <windows.h> -+ #include <winreg.h> -+-#define DIR_SEP "\\" -+-#else -+-#define DIR_SEP "/" -+ #endif -+ -+ #ifdef HAVE_BDJ_J2ME -+@@ -67,7 +65,7 @@ static void *_load_jvm_win32(const char **p_java_home) -+ -+ wchar_t buf_loc[4096] = L"SOFTWARE\\JavaSoft\\Java Runtime Environment\\"; -+ wchar_t buf_vers[128]; -+- -++ wchar_t java_path[4096] = L""; -+ char strbuf[256]; -+ -+ LONG r; -+@@ -77,14 +75,14 @@ static void *_load_jvm_win32(const char **p_java_home) -+ -+ r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buf_loc, 0, KEY_READ, &hkey); -+ if (r != ERROR_SUCCESS) { -+- BD_DEBUG(DBG_BDJ | DBG_CRIT, "Error opening registry key SOFTWARE\\JavaSoft\\Java Runtime Environment\\"); -++ BD_DEBUG(DBG_BDJ | DBG_CRIT, "Error opening registry key SOFTWARE\\JavaSoft\\Java Runtime Environment\\\n"); -+ return NULL; -+ } -+ -+ r = RegQueryValueExW(hkey, L"CurrentVersion", NULL, &lType, (LPBYTE)buf_vers, &dSize); -+ RegCloseKey(hkey); -+ if (r != ERROR_SUCCESS) { -+- BD_DEBUG(DBG_BDJ | DBG_CRIT, "CurrentVersion registry value not found"); -++ BD_DEBUG(DBG_BDJ | DBG_CRIT, "CurrentVersion registry value not found\n"); -+ return NULL; -+ } -+ -+@@ -97,7 +95,7 @@ static void *_load_jvm_win32(const char **p_java_home) -+ dSize = sizeof(buf_loc); -+ r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buf_loc, 0, KEY_READ, &hkey); -+ if (r != ERROR_SUCCESS) { -+- BD_DEBUG(DBG_BDJ | DBG_CRIT, "Error opening JRE version-specific registry key"); -++ BD_DEBUG(DBG_BDJ | DBG_CRIT, "Error opening JRE version-specific registry key\n"); -+ return NULL; -+ } -+ -+@@ -108,6 +106,9 @@ static void *_load_jvm_win32(const char **p_java_home) -+ WideCharToMultiByte(CP_UTF8, 0, buf_loc, -1, java_home, sizeof(java_home), NULL, NULL); -+ *p_java_home = java_home; -+ BD_DEBUG(DBG_BDJ, "JavaHome: %s\n", java_home); -++ -++ wcscat(java_path, buf_loc); -++ wcscat(java_path, L"\\bin"); -+ } -+ -+ dSize = sizeof(buf_loc); -+@@ -115,11 +116,13 @@ static void *_load_jvm_win32(const char **p_java_home) -+ RegCloseKey(hkey); -+ -+ if (r != ERROR_SUCCESS) { -+- BD_DEBUG(DBG_BDJ | DBG_CRIT, "RuntimeLib registry value not found"); -++ BD_DEBUG(DBG_BDJ | DBG_CRIT, "RuntimeLib registry value not found\n"); -+ return NULL; -+ } -+ -++ SetDllDirectoryW(java_path); -+ void *result = LoadLibraryW(buf_loc); -++ SetDllDirectoryW(NULL); -+ -+ WideCharToMultiByte(CP_UTF8, 0, buf_loc, -1, strbuf, sizeof(strbuf), NULL, NULL); -+ if (!result) { -+@@ -132,10 +135,43 @@ static void *_load_jvm_win32(const char **p_java_home) -+ } -+ #endif -+ -++#ifdef _WIN32 -++static inline char *_utf8_to_cp(const char *utf8) -++{ -++ int wlen = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0); -++ if (wlen == 0) { -++ return NULL; -++ } -++ -++ wchar_t *wide = (wchar_t *)malloc(wlen * sizeof(wchar_t)); -++ if (!wide) { -++ return NULL; -++ } -++ MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wide, wlen); -++ -++ size_t len = WideCharToMultiByte(CP_ACP, 0, wide, -1, NULL, 0, NULL, NULL); -++ if (len == 0) { -++ X_FREE(wide); -++ return NULL; -++ } -++ -++ char *out = (char *)malloc(len); -++ if (out != NULL) { -++ WideCharToMultiByte(CP_ACP, 0, wide, -1, out, len, NULL, NULL); -++ } -++ X_FREE(wide); -++ return out; -++} -++#endif -++ -+ static void *_jvm_dlopen(const char *java_home, const char *jvm_dir, const char *jvm_lib) -+ { -+ if (java_home) { -+ char *path = str_printf("%s/%s/%s", java_home, jvm_dir, jvm_lib); -++ if (!path) { -++ BD_DEBUG(DBG_CRIT, "out of memory\n"); -++ return NULL; -++ } -+ BD_DEBUG(DBG_BDJ, "Opening %s ...\n", path); -+ void *h = dl_dlopen(path, NULL); -+ X_FREE(path); -+@@ -208,11 +244,17 @@ static void *_load_jvm(const char **p_java_home) -+ -+ static int _can_read_file(const char *fn) -+ { -+- FILE *fp = fopen(fn, "rb"); -++ BD_FILE_H *fp; -++ -++ if (!fn) { -++ return 0; -++ } -++ -++ fp = file_open(fn, "rb"); -+ if (fp) { -+- char b; -+- int result = (int)fread(&b, 1, 1, fp); -+- fclose(fp); -++ uint8_t b; -++ int result = (int)file_read(fp, &b, 1); -++ file_close(fp); -+ if (result == 1) { -+ return 1; -+ } -+@@ -460,6 +502,11 @@ static int _create_jvm(void *jvm_lib, const char *java_home, const char *jar_fil -+ } -+ -+ JavaVMOption* option = calloc(1, sizeof(JavaVMOption) * 20); -++ if (!option) { -++ BD_DEBUG(DBG_CRIT, "out of memory\n"); -++ return 0; -++ } -++ -+ int n = 0; -+ JavaVMInitArgs args; -+ option[n++].optionString = str_dup ("-Dawt.toolkit=java.awt.BDToolkit"); -+@@ -499,6 +546,17 @@ static int _create_jvm(void *jvm_lib, const char *java_home, const char *jar_fil -+ args.options = option; -+ args.ignoreUnrecognized = JNI_FALSE; // don't ignore unrecognized options -+ -++#ifdef _WIN32 -++ /* ... in windows, JVM options are not UTF8 but current system code page ... */ -++ /* luckily, most BD-J options can be passed in as java strings later. But, not class path. */ -++ int ii; -++ for (ii = 0; ii < n; ii++) { -++ char *tmp = _utf8_to_cp(option[ii].optionString); -++ X_FREE(option[ii].optionString); -++ option[ii].optionString = tmp; -++ } -++#endif -++ -+ int result = JNI_CreateJavaVM_fp(jvm, (void**) env, &args); -+ -+ while (--n >= 0) { -+@@ -534,16 +592,22 @@ BDJAVA* bdj_open(const char *path, struct bluray *bd, -+ return 0; -+ } -+ -++ BDJAVA* bdjava = calloc(1, sizeof(BDJAVA)); -++ if (!bdjava) { -++ dl_dlclose(jvm_lib); -++ return NULL; -++ } -++ -+ JNIEnv* env = NULL; -+ JavaVM *jvm = NULL; -+ if (!_find_jvm(jvm_lib, &env, &jvm) && -+ !_create_jvm(jvm_lib, java_home, jar_file, &env, &jvm)) { -+ -++ X_FREE(bdjava); -+ dl_dlclose(jvm_lib); -+ return NULL; -+ } -+ -+- BDJAVA* bdjava = calloc(1, sizeof(BDJAVA)); -+ bdjava->h_libjvm = jvm_lib; -+ bdjava->jvm = jvm; -+ -+diff --git a/src/libbluray/bdj/bdj.h b/src/libbluray/bdj/bdj.h -+index 45fbfc5..f6cd97b 100644 -+--- a/src/libbluray/bdj/bdj.h -++++ b/src/libbluray/bdj/bdj.h -+@@ -45,10 +45,10 @@ typedef enum { -+ } BDJ_EVENT; -+ -+ typedef struct { -+- char *persistent_root; -+- char *cache_root; -++ char *persistent_root; /* BD-J Xlet persistent storage */ -++ char *cache_root; /* BD-J binding unit data area */ -+ -+- char *classpath; -++ char *classpath; /* BD-J implementation class path (location of libbluray.jar) */ -+ } BDJ_STORAGE; -+ -+ typedef struct bdjava_s BDJAVA; -+diff --git a/src/libbluray/bdj/build.xml b/src/libbluray/bdj/build.xml -+index c2764f7..938cd44 100644 -+--- a/src/libbluray/bdj/build.xml -++++ b/src/libbluray/bdj/build.xml -+@@ -7,6 +7,7 @@ -+ <property name="build" location="build"/> -+ <property name="dist" location="../../.libs"/> -+ <property name="src_awt" value=""/> -++ <property name="src_asm" value="../../../contrib/asm/src/"/> -+ <property name="bootclasspath" value=""/> -+ <property name="version" value=""/> -+ -+@@ -18,6 +19,12 @@ -+ -+ <target name="compile" depends="init" -+ description="compile the source " > -++ <javac srcdir="${src_asm}" destdir="${build}" debug="yes" -++ bootclasspath="${bootclasspath}" -++ source="1.5" target="1.5"> -++ <compilerarg value="-XDignore.symbol.file"/> -++ <compilerarg value="-Xlint:-deprecation"/> -++ </javac> -+ <javac srcdir="${src}${src_awt}" destdir="${build}" debug="yes" -+ bootclasspath="${bootclasspath}" -+ source="1.4" target="1.4"> -+diff --git a/src/libbluray/bdj/java-j2se/java/awt/BDGraphics.java b/src/libbluray/bdj/java-j2se/java/awt/BDGraphics.java -+index 54c24e5..77ce66e 100644 -+--- a/src/libbluray/bdj/java-j2se/java/awt/BDGraphics.java -++++ b/src/libbluray/bdj/java-j2se/java/awt/BDGraphics.java -+@@ -53,6 +53,7 @@ class BDGraphics extends BDGraphicsBase { -+ -+ public java.awt.font.FontRenderContext getFontRenderContext() -+ { -++ logger.unimplemented("getFontRenderContext"); -+ return null; -+ } -+ public void setPaint(Paint p) { -+diff --git a/src/libbluray/bdj/java/com/aacsla/bluray/online/ContentAttribute.java b/src/libbluray/bdj/java/com/aacsla/bluray/online/ContentAttribute.java -+index fbfa45d..34f59e4 100644 -+--- a/src/libbluray/bdj/java/com/aacsla/bluray/online/ContentAttribute.java -++++ b/src/libbluray/bdj/java/com/aacsla/bluray/online/ContentAttribute.java -+@@ -27,10 +27,33 @@ public class ContentAttribute { -+ } -+ -+ public byte[] getContentCertID() { -++ byte[] id = getContentCertID("AACS" + File.separator + "Content000.cer"); -++ if (id != null) { -++ return id; -++ } -++ -++ id = getContentCertID("MAKEMKV" + File.separator + "AACS" + File.separator + "Content000.cer"); -++ if (id != null) { -++ return id; -++ } -++ -++ id = getContentCertID("ANY!" + File.separator + "Content000.cer"); -++ if (id != null) { -++ return id; -++ } -++ -++ return new byte[6]; -++ } -++ -++ private byte[] getContentCertID(String file) { -+ FileInputStream is = null; -+ try { -+ is = new FileInputStream( -+- System.getProperty("bluray.vfs.root") + File.separator + "AACS/Content000.cer"); -++ System.getProperty("bluray.vfs.root") + File.separator + file); -++ } catch (Exception e) { -++ return null; -++ } -++ try { -+ if (is.skip(14) != 14) -+ return null; -+ byte[] bytes = new byte[6]; -+diff --git a/src/libbluray/bdj/java/java/awt/BDFontMetrics.java b/src/libbluray/bdj/java/java/awt/BDFontMetrics.java -+index d2a91dc..fdcda44 100644 -+--- a/src/libbluray/bdj/java/java/awt/BDFontMetrics.java -++++ b/src/libbluray/bdj/java/java/awt/BDFontMetrics.java -+@@ -192,7 +192,12 @@ public class BDFontMetrics extends sun.font.FontDesignMetrics { -+ } -+ -+ static synchronized String[] getFontList() { -+- init(); -++ try { -++ init(); -++ } catch (Throwable t) { -++ System.err.println("getFontList() failed: " + t); -++ return new String[0]; -++ } -+ -+ ArrayList fontNames = new ArrayList(); -+ -+diff --git a/src/libbluray/bdj/java/java/awt/BDGraphicsBase.java b/src/libbluray/bdj/java/java/awt/BDGraphicsBase.java -+index 0c7d403..f7e60f7 100644 -+--- a/src/libbluray/bdj/java/java/awt/BDGraphicsBase.java -++++ b/src/libbluray/bdj/java/java/awt/BDGraphicsBase.java -+@@ -306,7 +306,7 @@ abstract class BDGraphicsBase extends Graphics2D implements ConstrainableGraphic -+ Rectangle rect = new Rectangle(x, y, length, 1); -+ rect = actualClip.intersection(rect); -+ -+- if (rect.width <= 0 || rect.height <= 0 || rect.x < 0 || rect.y < 0) { -++ if (rect.width <= 0 || rect.height <= 0 || rect.x < 0 || rect.y < 0 || backBuffer == null) { -+ return; -+ } -+ -+@@ -364,7 +364,7 @@ abstract class BDGraphicsBase extends Graphics2D implements ConstrainableGraphic -+ Rectangle rect = new Rectangle(x, y, length, 1); -+ rect = actualClip.intersection(rect); -+ -+- if (rect.width <= 0 || rect.height <= 0 || rect.x < 0 || rect.y < 0) { -++ if (rect.width <= 0 || rect.height <= 0 || rect.x < 0 || rect.y < 0 || backBuffer == null) { -+ return; -+ } -+ -+@@ -458,7 +458,7 @@ abstract class BDGraphicsBase extends Graphics2D implements ConstrainableGraphic -+ y += originY; -+ Rectangle rect = new Rectangle(x, y, w, h); -+ rect = actualClip.intersection(rect); -+- if (rect.isEmpty()) { -++ if (rect.isEmpty() || backBuffer == null) { -+ return; -+ } -+ x = rect.x; -+@@ -572,7 +572,7 @@ abstract class BDGraphicsBase extends Graphics2D implements ConstrainableGraphic -+ Rectangle rect = new Rectangle(x, y, w, h); -+ rect = actualClip.intersection(rect); -+ -+- if (rect.width <= 0 || rect.height <= 0) { -++ if (rect.width <= 0 || rect.height <= 0 || backBuffer == null) { -+ return; -+ } -+ -+diff --git a/src/libbluray/bdj/java/java/awt/BDImageConsumer.java b/src/libbluray/bdj/java/java/awt/BDImageConsumer.java -+index 59e2af3..a076873 100644 -+--- a/src/libbluray/bdj/java/java/awt/BDImageConsumer.java -++++ b/src/libbluray/bdj/java/java/awt/BDImageConsumer.java -+@@ -25,7 +25,7 @@ import java.awt.image.ImageObserver; -+ import java.awt.image.ImageConsumer; -+ import java.awt.image.ColorModel; -+ -+-public class BDImageConsumer extends BDImage implements ImageConsumer { -++class BDImageConsumer extends BDImage implements ImageConsumer { -+ private Hashtable properties; -+ private ImageProducer producer; -+ private int status; -+diff --git a/src/libbluray/bdj/java/java/awt/BDToolkitBase.java b/src/libbluray/bdj/java/java/awt/BDToolkitBase.java -+index e210dea..0f5e3e0 100644 -+--- a/src/libbluray/bdj/java/java/awt/BDToolkitBase.java -++++ b/src/libbluray/bdj/java/java/awt/BDToolkitBase.java -+@@ -124,6 +124,10 @@ abstract class BDToolkitBase extends Toolkit { -+ } -+ -+ public Image getImage(String filename) { -++ if (BDJXletContext.getCurrentContext() == null) { -++ logger.error("getImage(): no context " + Logger.dumpStack()); -++ } -++ -+ if (cachedImages.containsKey(filename)) -+ return (Image)cachedImages.get(filename); -+ Image newImage = createImage(filename); -+@@ -133,6 +137,10 @@ abstract class BDToolkitBase extends Toolkit { -+ } -+ -+ public Image getImage(URL url) { -++ if (BDJXletContext.getCurrentContext() == null) { -++ logger.error("getImage(): no context " + Logger.dumpStack()); -++ } -++ -+ if (cachedImages.containsKey(url)) -+ return (Image)cachedImages.get(url); -+ Image newImage = createImage(url); -+@@ -142,6 +150,10 @@ abstract class BDToolkitBase extends Toolkit { -+ } -+ -+ public Image createImage(String filename) { -++ if (BDJXletContext.getCurrentContext() == null) { -++ logger.error("createImage(): no context " + Logger.dumpStack()); -++ } -++ -+ if (!new File(filename).isAbsolute()) { -+ String home = BDJXletContext.getCurrentXletHome(); -+ if (home != null) { -+@@ -161,6 +173,9 @@ abstract class BDToolkitBase extends Toolkit { -+ } -+ -+ public Image createImage(URL url) { -++ if (BDJXletContext.getCurrentContext() == null) { -++ logger.error("createImage(): no context " + Logger.dumpStack()); -++ } -+ ImageProducer ip = new URLImageSource(url); -+ Image newImage = createImage(ip); -+ return newImage; -+@@ -169,12 +184,20 @@ abstract class BDToolkitBase extends Toolkit { -+ public Image createImage(byte[] imagedata, -+ int imageoffset, -+ int imagelength) { -++ -++ if (BDJXletContext.getCurrentContext() == null) { -++ logger.error("createImage(): no context " + Logger.dumpStack()); -++ } -++ -+ ImageProducer ip = new ByteArrayImageSource(imagedata, imageoffset, imagelength); -+ Image newImage = createImage(ip); -+ return newImage; -+ } -+ -+ public Image createImage(ImageProducer producer) { -++ if (BDJXletContext.getCurrentContext() == null) { -++ logger.error("createImage(): no context " + Logger.dumpStack()); -++ } -+ return new BDImageConsumer(producer); -+ } -+ -+@@ -243,7 +266,7 @@ abstract class BDToolkitBase extends Toolkit { -+ } -+ } -+ -+- logger.warning("getSystemEventQueue(): no context"); -++ logger.warning("getSystemEventQueue(): no context from:" + logger.dumpStack()); -+ return eventQueue; -+ } -+ } -+diff --git a/src/libbluray/bdj/java/java/awt/BDWindowGraphics.java b/src/libbluray/bdj/java/java/awt/BDWindowGraphics.java -+index 743f441..26e7248 100644 -+--- a/src/libbluray/bdj/java/java/awt/BDWindowGraphics.java -++++ b/src/libbluray/bdj/java/java/awt/BDWindowGraphics.java -+@@ -39,6 +39,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void clearRect(int x, int y, int w, int h) { -++ if (window == null) return; -+ synchronized (window) { -+ super.clearRect(x, y, w, h); -+ window.notifyChanged(); -+@@ -46,6 +47,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void fillRect(int x, int y, int w, int h) { -++ if (window == null) return; -+ synchronized (window) { -+ super.fillRect(x, y, w, h); -+ window.notifyChanged(); -+@@ -53,6 +55,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void drawRect(int x, int y, int w, int h) { -++ if (window == null) return; -+ synchronized (window) { -+ super.drawRect(x, y, w, h); -+ window.notifyChanged(); -+@@ -60,6 +63,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void drawLine(int x1, int y1, int x2, int y2) { -++ if (window == null) return; -+ synchronized (window) { -+ super.drawLine(x1, y1, x2, y2); -+ window.notifyChanged(); -+@@ -67,6 +71,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void copyArea(int x, int y, int w, int h, int dx, int dy) { -++ if (window == null) return; -+ synchronized (window) { -+ super.copyArea(x, y, w, h, dx, dy); -+ window.notifyChanged(); -+@@ -74,6 +79,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void drawPolyline(int xPoints[], int yPoints[], int nPoints) { -++ if (window == null) return; -+ synchronized (window) { -+ super.drawPolyline(xPoints, yPoints, nPoints); -+ window.notifyChanged(); -+@@ -81,6 +87,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void drawPolygon(int xPoints[], int yPoints[], int nPoints) { -++ if (window == null) return; -+ synchronized (window) { -+ super.drawPolygon(xPoints, yPoints, nPoints); -+ window.notifyChanged(); -+@@ -88,6 +95,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void fillPolygon(int xPoints[], int yPoints[], int nPoints) { -++ if (window == null) return; -+ synchronized (window) { -+ super.fillPolygon(xPoints, yPoints, nPoints); -+ window.notifyChanged(); -+@@ -95,6 +103,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void drawOval(int x, int y, int w, int h) { -++ if (window == null) return; -+ synchronized (window) { -+ super.drawOval(x, y, w, h); -+ window.notifyChanged(); -+@@ -102,6 +111,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void fillOval(int x, int y, int w, int h) { -++ if (window == null) return; -+ synchronized (window) { -+ super.fillOval(x, y, w, h); -+ window.notifyChanged(); -+@@ -109,6 +119,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void drawArc(int x, int y, int w, int h, int startAngle, int endAngle) { -++ if (window == null) return; -+ synchronized (window) { -+ super.drawArc(x, y, w, h, startAngle, endAngle); -+ window.notifyChanged(); -+@@ -116,6 +127,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void fillArc(int x, int y, int w, int h, int startAngle, int endAngle) { -++ if (window == null) return; -+ synchronized (window) { -+ super.fillArc(x, y, w, h, startAngle, endAngle); -+ window.notifyChanged(); -+@@ -123,6 +135,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void drawRoundRect(int x, int y, int w, int h, int arcWidth, int arcHeight) { -++ if (window == null) return; -+ synchronized (window) { -+ super.drawRoundRect(x, y, w, h, arcWidth, arcHeight); -+ window.notifyChanged(); -+@@ -130,6 +143,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ public void fillRoundRect(int x, int y, int w, int h, int arcWidth, int arcHeight) { -++ if (window == null) return; -+ synchronized (window) { -+ super.fillRoundRect(x, y, w, h, arcWidth, arcHeight); -+ window.notifyChanged(); -+@@ -137,6 +151,7 @@ public class BDWindowGraphics extends BDGraphics { -+ } -+ -+ protected void drawStringN(long ftFace, String string, int x, int y, int rgb) { -++ if (window == null) return; -+ synchronized (window) { -+ super.drawStringN(ftFace, string, x, y, rgb); -+ window.notifyChanged(); -+@@ -154,6 +169,8 @@ public class BDWindowGraphics extends BDGraphics { -+ boolean flipX, boolean flipY, -+ Color bg, ImageObserver observer) { -+ -++ if (window == null) return true; -++ -+ synchronized (window) { -+ boolean complete = super.drawImageN( -+ img, dx, dy, dw, dh, sx, sy, sw, sh, -+diff --git a/src/libbluray/bdj/java/java/awt/Font.java b/src/libbluray/bdj/java/java/awt/Font.java -+index a126bc5..a952599 100644 -+--- a/src/libbluray/bdj/java/java/awt/Font.java -++++ b/src/libbluray/bdj/java/java/awt/Font.java -+@@ -198,6 +198,9 @@ public class Font implements java.io.Serializable { -+ public Font deriveFont(int style, int size) { -+ return new Font(name, style, size, fontFile, family); -+ } -++ public Font deriveFont(int style, float size) { -++ return new Font(name, style, (int)size, fontFile, family); -++ } -+ -+ /* constructor */ -+ private Font(String name, int style, int size, File fontFile, String family) { -+diff --git a/src/libbluray/bdj/java/javax/media/MediaLocator.java b/src/libbluray/bdj/java/javax/media/MediaLocator.java -+index a182e8d..245ac54 100644 -+--- a/src/libbluray/bdj/java/javax/media/MediaLocator.java -++++ b/src/libbluray/bdj/java/javax/media/MediaLocator.java -+@@ -25,11 +25,11 @@ import java.net.URL; -+ -+ public class MediaLocator implements Serializable -+ { -+- public MediaLocator(URL url) { -++ public MediaLocator(URL url) { -+ this(url.toExternalForm()); -+ } -+ -+- public MediaLocator(String locatorString) { -++ public MediaLocator(String locatorString) { -+ int index = locatorString.indexOf(":"); -+ if (index <= 0) -+ throw new IllegalArgumentException("Bad locator string."); -+@@ -56,7 +56,7 @@ public class MediaLocator implements Serializable -+ public String toExternalForm() { -+ return protocol + ":" + remainder; -+ } -+- -++ -+ private String protocol = ""; -+ private String remainder = ""; -+ -+diff --git a/src/libbluray/bdj/java/javax/tv/graphics/TVContainer.java b/src/libbluray/bdj/java/javax/tv/graphics/TVContainer.java -+index e036884..09971b6 100644 -+--- a/src/libbluray/bdj/java/javax/tv/graphics/TVContainer.java -++++ b/src/libbluray/bdj/java/javax/tv/graphics/TVContainer.java -+@@ -20,9 +20,10 @@ package javax.tv.graphics; -+ -+ import java.awt.Container; -+ import javax.tv.xlet.XletContext; -+-import org.havi.ui.HScene; -+ import org.havi.ui.HSceneFactory; -+ -++import org.videolan.BDJXletContext; -++ -+ public class TVContainer { -+ public static Container getRootContainer(XletContext context) -+ { -+@@ -30,7 +31,15 @@ public class TVContainer { -+ throw new NullPointerException(); -+ } -+ -+- HScene scene = HSceneFactory.getInstance().getDefaultHScene(); -+- return scene; -++ if (!(context instanceof BDJXletContext) || (BDJXletContext)context != BDJXletContext.getCurrentContext()) { -++ org.videolan.Logger.getLogger(TVContainer.class.getName()).error("wrong context"); -++ } -++ -++ /* GEM: return instance of org.havi.ui.HScene or NULL */ -++ HSceneFactory sf = HSceneFactory.getInstance(); -++ if (sf != null) { -++ return sf.getDefaultHScene(); -++ } -++ return null; -+ } -+ } -+diff --git a/src/libbluray/bdj/java/javax/tv/locator/LocatorImpl.java b/src/libbluray/bdj/java/javax/tv/locator/LocatorImpl.java -+index e14825c..a87269a 100644 -+--- a/src/libbluray/bdj/java/javax/tv/locator/LocatorImpl.java -++++ b/src/libbluray/bdj/java/javax/tv/locator/LocatorImpl.java -+@@ -24,7 +24,7 @@ public class LocatorImpl implements Locator { -+ this.url = url; -+ } -+ -+- public boolean hasMultipleTransformations() { -++ public boolean hasMultipleTransformations() { -+ return false; -+ } -+ -+diff --git a/src/libbluray/bdj/java/javax/tv/service/SIElement.java b/src/libbluray/bdj/java/javax/tv/service/SIElement.java -+index c2a0262..16140de 100644 -+--- a/src/libbluray/bdj/java/javax/tv/service/SIElement.java -++++ b/src/libbluray/bdj/java/javax/tv/service/SIElement.java -+@@ -26,7 +26,7 @@ public interface SIElement extends SIRetrievable -+ public Locator getLocator(); -+ -+ public boolean equals(Object obj); -+- -++ -+ public int hashCode(); -+ -+ public ServiceInformationType getServiceInformationType(); -+diff --git a/src/libbluray/bdj/java/javax/tv/service/SIManagerImpl.java b/src/libbluray/bdj/java/javax/tv/service/SIManagerImpl.java -+index 4016876..f9d4a32 100644 -+--- a/src/libbluray/bdj/java/javax/tv/service/SIManagerImpl.java -++++ b/src/libbluray/bdj/java/javax/tv/service/SIManagerImpl.java -+@@ -29,6 +29,7 @@ import javax.tv.service.navigation.ServiceListImpl; -+ import javax.tv.service.transport.Transport; -+ import javax.tv.service.transport.TransportImpl; -+ -++import org.bluray.net.BDLocator; -+ import org.bluray.ti.TitleImpl; -+ import org.videolan.Libbluray; -+ -+@@ -82,6 +83,15 @@ public class SIManagerImpl extends SIManager { -+ } -+ -+ public Service getService(Locator locator) throws InvalidLocatorException, SecurityException { -++ -++ BDLocator bdLocator = null; -++ try { -++ bdLocator = new BDLocator(locator.toExternalForm()); -++ } catch (org.davic.net.InvalidLocatorException e) { -++ System.err.println("invalid locator: " + locator.toExternalForm() + "\n" + org.videolan.Logger.dumpStack(e)); -++ throw new javax.tv.locator.InvalidLocatorException(locator); -++ } -++ -+ return titles.findService(locator); -+ } -+ -+diff --git a/src/libbluray/bdj/java/javax/tv/service/navigation/SIElementFilter.java b/src/libbluray/bdj/java/javax/tv/service/navigation/SIElementFilter.java -+index fdfa128..f0dc97c 100644 -+--- a/src/libbluray/bdj/java/javax/tv/service/navigation/SIElementFilter.java -++++ b/src/libbluray/bdj/java/javax/tv/service/navigation/SIElementFilter.java -+@@ -1,6 +1,7 @@ -+ /* -+ * This file is part of libbluray -+ * Copyright (C) 2010 William Hahne -++ * Copyright (C) 2015 Petri Hintukainen -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+@@ -25,9 +26,21 @@ import javax.tv.service.SIElement; -+ import javax.tv.service.SIRequest; -+ import javax.tv.service.SIRequestorImpl; -+ -++import org.bluray.net.BDLocator; -++ -+ public final class SIElementFilter extends ServiceFilter -+ { -+ public SIElementFilter(SIElement element) throws FilterNotSupportedException { -++ if (element == null) -++ throw new NullPointerException(); -++ -++ try { -++ new BDLocator(element.getLocator().toExternalForm()); -++ } catch (Exception e) { -++ System.err.println("Invalid SI element: " + e + " at " + org.videolan.Logger.dumpStack(e)); -++ throw new FilterNotSupportedException(); -++ } -++ -+ this.element = element; -+ } -+ -+@@ -37,9 +50,9 @@ public final class SIElementFilter extends ServiceFilter -+ -+ public boolean accept(Service service) { -+ SIRequestorImpl requestor = new SIRequestorImpl(); -+- -++ -+ SIRequest req = service.retrieveDetails(requestor); -+- -++ -+ // TODO: This may be a bit excessive -+ int timeout = 0; -+ while (!requestor.getResponse() && timeout < 1000) { -+@@ -48,27 +61,27 @@ public final class SIElementFilter extends ServiceFilter -+ } catch (InterruptedException e) { -+ // ignore -+ } -+- -++ -+ timeout++; -+ } -+- -++ -+ // if we still don't have a response just cancel the request -+ if (!requestor.getResponse()) { -+ if (req != null) -+ req.cancel(); -+ } -+- -++ -+ if (requestor.getResult() == null) -+ return false; -+- -++ -+ SIRetrievable[] rets = requestor.getResult(); -+ for (int i = 0; i < rets.length; i++) { -+ if (rets[i].equals(element)) -+ return true; -+ } -+- -++ -+ return false; -+ } -+- -++ -+ SIElement element; -+ } -+diff --git a/src/libbluray/bdj/java/javax/tv/service/navigation/ServiceTypeFilter.java b/src/libbluray/bdj/java/javax/tv/service/navigation/ServiceTypeFilter.java -+index 0333302..250821e 100644 -+--- a/src/libbluray/bdj/java/javax/tv/service/navigation/ServiceTypeFilter.java -++++ b/src/libbluray/bdj/java/javax/tv/service/navigation/ServiceTypeFilter.java -+@@ -24,6 +24,8 @@ import javax.tv.service.ServiceType; -+ public final class ServiceTypeFilter extends ServiceFilter { -+ public ServiceTypeFilter(ServiceType type) -+ { -++ if (type == null) -++ throw new NullPointerException(); -+ this.type = type; -+ } -+ -+diff --git a/src/libbluray/bdj/java/javax/tv/service/navigation/StreamType.java b/src/libbluray/bdj/java/javax/tv/service/navigation/StreamType.java -+index 5824b44..26dc166 100644 -+--- a/src/libbluray/bdj/java/javax/tv/service/navigation/StreamType.java -++++ b/src/libbluray/bdj/java/javax/tv/service/navigation/StreamType.java -+@@ -22,6 +22,8 @@ package javax.tv.service.navigation; -+ public class StreamType { -+ protected StreamType(String name) -+ { -++ if (name == null) -++ throw new NullPointerException(); -+ this.name = name; -+ } -+ -+diff --git a/src/libbluray/bdj/java/javax/tv/service/selection/ServiceContextFactoryImpl.java b/src/libbluray/bdj/java/javax/tv/service/selection/ServiceContextFactoryImpl.java -+index e1e8dea..2940db4 100644 -+--- a/src/libbluray/bdj/java/javax/tv/service/selection/ServiceContextFactoryImpl.java -++++ b/src/libbluray/bdj/java/javax/tv/service/selection/ServiceContextFactoryImpl.java -+@@ -33,12 +33,14 @@ public class ServiceContextFactoryImpl extends ServiceContextFactory { -+ synchronized (ServiceContextFactoryImpl.class) { -+ if (instance == null) -+ instance = new ServiceContextFactoryImpl(); -++ return instance; -+ } -+- return instance; -+ } -+ -+ public static void shutdown() { -+- instance = null; -++ synchronized (ServiceContextFactoryImpl.class) { -++ instance = null; -++ } -+ } -+ -+ public ServiceContext createServiceContext() -+@@ -60,10 +62,19 @@ public class ServiceContextFactoryImpl extends ServiceContextFactory { -+ } -+ -+ public ServiceContext[] getServiceContexts() { -+- SecurityManager sec = System.getSecurityManager(); -+- if (sec != null) -+- sec.checkPermission(new ServiceContextPermission("access", "own")); -+- return serviceContexts; -++ try { -++ SecurityManager sec = System.getSecurityManager(); -++ if (sec != null) -++ sec.checkPermission(new ServiceContextPermission("access", "own")); -++ -++ ServiceContext[] r = new ServiceContext[1]; -++ r[0] = serviceContexts[0]; -++ return r; -++ -++ } catch (Exception e) { -++ } -++ -++ return new ServiceContext[0]; -+ } -+ -+ private ServiceContext[] serviceContexts; -+diff --git a/src/libbluray/bdj/java/org/bluray/bdplus/Status.java b/src/libbluray/bdj/java/org/bluray/bdplus/Status.java -+index 3f5fcf6..b897b3e 100644 -+--- a/src/libbluray/bdj/java/org/bluray/bdplus/Status.java -++++ b/src/libbluray/bdj/java/org/bluray/bdplus/Status.java -+@@ -28,8 +28,8 @@ public class Status { -+ synchronized (Status.class) { -+ if (instance == null) -+ instance = new Status(); -++ return instance; -+ } -+- return instance; -+ } -+ -+ public static void shutdown() { -+diff --git a/src/libbluray/bdj/java/org/bluray/net/BDLocator.java b/src/libbluray/bdj/java/org/bluray/net/BDLocator.java -+index 6b747cc..a0b593b 100644 -+--- a/src/libbluray/bdj/java/org/bluray/net/BDLocator.java -++++ b/src/libbluray/bdj/java/org/bluray/net/BDLocator.java -+@@ -29,11 +29,11 @@ public class BDLocator extends Locator { -+ super(url); -+ try { -+ -+- if (!url.startsWith("bd://")) -+- throw new InvalidLocatorException(); -+- String str = url.substring(5); -+- if (!parseJar(str) && !parseSound(str) && !parsePlaylist(str)) -+- throw new InvalidLocatorException(); -++ if (!url.startsWith("bd://")) -++ throw new InvalidLocatorException(); -++ String str = url.substring(5); -++ if (!parseJar(str) && !parseSound(str) && !parsePlaylist(str)) -++ throw new InvalidLocatorException(); -+ -+ } catch (InvalidLocatorException e) { -+ System.err.println("Invalid locator: " + url); -+diff --git a/src/libbluray/bdj/java/org/bluray/storage/StorageManager.java b/src/libbluray/bdj/java/org/bluray/storage/StorageManager.java -+index 961c8ec..5ea1c57 100644 -+--- a/src/libbluray/bdj/java/org/bluray/storage/StorageManager.java -++++ b/src/libbluray/bdj/java/org/bluray/storage/StorageManager.java -+@@ -24,8 +24,8 @@ public class StorageManager { -+ synchronized (StorageManager.class) { -+ if (instance == null) -+ instance = new StorageManager(); -++ return instance; -+ } -+- return instance; -+ } -+ -+ protected StorageManager() { -+diff --git a/src/libbluray/bdj/java/org/bluray/ti/selection/TitleContextImpl.java b/src/libbluray/bdj/java/org/bluray/ti/selection/TitleContextImpl.java -+index 0109d2b..48d70be 100644 -+--- a/src/libbluray/bdj/java/org/bluray/ti/selection/TitleContextImpl.java -++++ b/src/libbluray/bdj/java/org/bluray/ti/selection/TitleContextImpl.java -+@@ -38,9 +38,11 @@ import javax.tv.service.selection.ServiceContextPermission; -+ -+ import org.bluray.ti.Title; -+ import org.bluray.ti.TitleImpl; -++ -+ import org.videolan.BDJLoader; -+ import org.videolan.BDJLoaderCallback; -+ import org.videolan.BDJListeners; -++import org.videolan.Logger; -+ import org.videolan.media.content.PlayerManager; -+ -+ public class TitleContextImpl implements TitleContext { -+@@ -71,19 +73,30 @@ public class TitleContextImpl implements TitleContext { -+ } -+ -+ public void start(Title title, boolean restart) throws SecurityException { -++ logger.info("start(" + title.getName() + ", restart=" + restart + ")"); -++ -+ SecurityManager sm = System.getSecurityManager(); -+ if (sm != null) { -+ sm.checkPermission(new SelectPermission(title.getLocator(), "own")); -+ } -+- -+- if (state == STATE_DESTROYED) -++ if (state == STATE_DESTROYED) { -++ logger.error("start() failed: Title Context already destroyed"); -+ throw new IllegalStateException(); -++ } -++ -++ if (!restart && (this.title == null || !title.equals(this.title))) { -++ /* force restarting of service bound Xlets when title changes */ -++ logger.info("start(): title changed, force restart"); -++ restart = true; -++ } -++ -+ TitleStartAction action = new TitleStartAction(this, (TitleImpl)title); -+ if (!BDJLoader.load((TitleImpl)title, restart, action)) -+ action.loaderDone(false); -+ } -+ -+ public void select(Service service) throws SecurityException { -++ logger.info("select(" + service.getName() + ")"); -+ start((Title)service, true); -+ } -+ -+@@ -96,6 +109,8 @@ public class TitleContextImpl implements TitleContext { -+ } -+ -+ public void stop() throws SecurityException { -++ logger.info("stop()"); -++ -+ SecurityManager sm = System.getSecurityManager(); -+ if (sm != null) { -+ sm.checkPermission(new ServiceContextPermission("stop", "own")); -+@@ -187,4 +202,6 @@ public class TitleContextImpl implements TitleContext { -+ private BDJListeners listeners = new BDJListeners(); -+ private TitleImpl title = null; -+ private int state = STATE_STOPPED; -++ -++ private static final Logger logger = Logger.getLogger(TitleContextImpl.class.getName()); -+ } -+diff --git a/src/libbluray/bdj/java/org/dvb/event/EventManager.java b/src/libbluray/bdj/java/org/dvb/event/EventManager.java -+index 2bf2ea4..844b72d 100644 -+--- a/src/libbluray/bdj/java/org/dvb/event/EventManager.java -++++ b/src/libbluray/bdj/java/org/dvb/event/EventManager.java -+@@ -40,8 +40,8 @@ public class EventManager implements ResourceServer { -+ synchronized (EventManager.class) { -+ if (instance == null) -+ instance = new EventManager(); -++ return instance; -+ } -+- return instance; -+ } -+ -+ public static void shutdown() { -+@@ -254,7 +254,7 @@ public class EventManager implements ResourceServer { -+ return false; -+ } -+ -+- private class UserEventItem { -++ private static class UserEventItem { -+ public UserEventItem(BDJXletContext context, UserEventListener listener, -+ ResourceClient client, UserEventRepository userEvents) { -+ this.context = context; -+@@ -272,7 +272,7 @@ public class EventManager implements ResourceServer { -+ public UserEventRepository userEvents; -+ } -+ -+- private class UserEventAction extends BDJAction { -++ private static class UserEventAction extends BDJAction { -+ public UserEventAction(UserEventItem item, UserEvent event) { -+ this.listener = item.listener; -+ this.event = event; -+diff --git a/src/libbluray/bdj/java/org/dvb/io/persistent/FileAttributes.java b/src/libbluray/bdj/java/org/dvb/io/persistent/FileAttributes.java -+index 4c941ff..65c3d29 100644 -+--- a/src/libbluray/bdj/java/org/dvb/io/persistent/FileAttributes.java -++++ b/src/libbluray/bdj/java/org/dvb/io/persistent/FileAttributes.java -+@@ -78,9 +78,9 @@ public class FileAttributes { -+ { -+ boolean r = f.canRead(); -+ boolean w = f.canWrite(); -+- -++ -+ FileAccessPermissions permissions = new FileAccessPermissions(r, w, r, w, r, w); -+- -++ -+ return new FileAttributes(null, permissions, PRIORITY_LOW); -+ } -+ -+diff --git a/src/libbluray/bdj/java/org/dvb/user/UserPreferenceManager.java b/src/libbluray/bdj/java/org/dvb/user/UserPreferenceManager.java -+index 239c966..af86b4e 100644 -+--- a/src/libbluray/bdj/java/org/dvb/user/UserPreferenceManager.java -++++ b/src/libbluray/bdj/java/org/dvb/user/UserPreferenceManager.java -+@@ -31,8 +31,8 @@ public class UserPreferenceManager { -+ synchronized (UserPreferenceManager.class) { -+ if (instance == null) -+ instance = new UserPreferenceManager(); -++ return instance; -+ } -+- return instance; -+ } -+ -+ public void read(Preference p) { -+diff --git a/src/libbluray/bdj/java/org/havi/ui/HScene.java b/src/libbluray/bdj/java/org/havi/ui/HScene.java -+index 7937d32..926781a 100644 -+--- a/src/libbluray/bdj/java/org/havi/ui/HScene.java -++++ b/src/libbluray/bdj/java/org/havi/ui/HScene.java -+@@ -239,8 +239,10 @@ public class HScene extends Container implements HComponentOrdering { -+ } -+ -+ public synchronized void dispose() { -+- if (null != BDJXletContext.getCurrentContext()) -+- HSceneFactory.getInstance().dispose(this); -++ HSceneFactory sf = HSceneFactory.getInstance(); -++ if (sf != null) { -++ sf.dispose(this); -++ } -+ } -+ -+ protected void disposeImpl() -+diff --git a/src/libbluray/bdj/java/org/videolan/BDJAppProxy.java b/src/libbluray/bdj/java/org/videolan/BDJAppProxy.java -+index 135c000..72ba458 100644 -+--- a/src/libbluray/bdj/java/org/videolan/BDJAppProxy.java -++++ b/src/libbluray/bdj/java/org/videolan/BDJAppProxy.java -+@@ -384,8 +384,8 @@ class BDJAppProxy implements DVBJProxy, Runnable { -+ } catch (InterruptedException e) { -+ } -+ } -++ return done; -+ } -+- return done; -+ } -+ -+ public void release() { -+diff --git a/src/libbluray/bdj/java/org/videolan/BDJAppsDatabase.java b/src/libbluray/bdj/java/org/videolan/BDJAppsDatabase.java -+index 13c088f..ca39f12 100644 -+--- a/src/libbluray/bdj/java/org/videolan/BDJAppsDatabase.java -++++ b/src/libbluray/bdj/java/org/videolan/BDJAppsDatabase.java -+@@ -35,8 +35,8 @@ public class BDJAppsDatabase extends AppsDatabase { -+ synchronized (BDJAppsDatabase.class) { -+ if (instance == null) -+ instance = new BDJAppsDatabase(); -++ return instance; -+ } -+- return instance; -+ } -+ -+ public int size() { -+@@ -106,5 +106,5 @@ public class BDJAppsDatabase extends AppsDatabase { -+ private BDJAppProxy[] appProxys = null; -+ private AppEntry[] appTable = null; -+ -+- protected static BDJAppsDatabase instance = null; -++ private static BDJAppsDatabase instance = null; -+ } -+diff --git a/src/libbluray/bdj/java/org/videolan/BDJClassFileTransformer.java b/src/libbluray/bdj/java/org/videolan/BDJClassFileTransformer.java -+new file mode 100644 -+index 0000000..988e76e -+--- /dev/null -++++ b/src/libbluray/bdj/java/org/videolan/BDJClassFileTransformer.java -+@@ -0,0 +1,91 @@ -++/* -++ * This file is part of libbluray -++ * Copyright (C) 2015 Petri Hintukainen <phintuka@users.sourceforge.net> -++ * -++ * This library is free software; you can redistribute it and/or -++ * modify it under the terms of the GNU Lesser General Public -++ * License as published by the Free Software Foundation; either -++ * version 2.1 of the License, or (at your option) any later version. -++ * -++ * This library is distributed in the hope that it will be useful, -++ * but WITHOUT ANY WARRANTY; without even the implied warranty of -++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -++ * Lesser General Public License for more details. -++ * -++ * You should have received a copy of the GNU Lesser General Public -++ * License along with this library. If not, see -++ * <http://www.gnu.org/licenses/>. -++ */ -++ -++package org.videolan; -++ -++/** -++ * This is a class which is called by BDJClassLoader -++ * when ClassFormatError is thrown inside defineClass(). -++ * -++ * Some discs have invalid debug info in class files (broken by -++ * malfunctioning obfuscater ?). -++ * We strip debug info from the class and try to load it again. -++ * -++ * Penguins of MAdagascar: -++ * java.lang.ClassFormatError: Invalid index 0 in LocalVariableTable' -++ * in class file com/tcs/blr/bluray/pal/fox/controller/d -++ */ -++ -++import org.objectweb.asm.ClassReader; -++import org.objectweb.asm.ClassWriter; -++import org.objectweb.asm.ClassVisitor; -++import org.objectweb.asm.MethodVisitor; -++import org.objectweb.asm.Opcodes; -++import org.objectweb.asm.Attribute; -++ -++class BDJClassFileTransformer -++{ -++ public byte[] transform(byte[] b, int off, int len) -++ throws ClassFormatError -++ { -++ logger.info("Trying to transform broken class file (" + len + " bytes)"); -++ -++ byte[] r = new byte[len]; -++ for (int i = 0; i < len; i++) -++ r[i] = b[i+off]; -++ -++ try { -++ ClassReader cr = new ClassReader(r); -++ ClassWriter cw = new ClassWriter(cr, 0/*ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS*/); -++ ClassVisitor cv = new MyClassVisitor(cw); -++ cr.accept(cv, ClassReader.SKIP_DEBUG); -++ return cw.toByteArray(); -++ } catch (Exception e) { -++ logger.error("Failed transforming class: " + e); -++ } -++ -++ return r; -++ } -++ -++ public class MyClassVisitor extends ClassVisitor { -++ public MyClassVisitor(ClassVisitor cv) { -++ super(Opcodes.ASM4, cv); -++ } -++ -++ public MethodVisitor visitMethod(int access, String name, String desc, -++ String signature, String[] exceptions) { -++ MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); -++ //System.err.println("visit method: " + name); -++ return new MyMethodVisitor(mv); -++ } -++ } -++ -++ public class MyMethodVisitor extends MethodVisitor { -++ public MyMethodVisitor(MethodVisitor mv) { -++ super(Opcodes.ASM4, mv); -++ } -++ -++ public void visitAttribute(Attribute attr) { -++ //System.err.println(" attribute: " + attr.type); -++ super.visitAttribute(attr); -++ } -++ } -++ -++ private static final Logger logger = Logger.getLogger(BDJClassFileTransformer.class.getName()); -++} -+diff --git a/src/libbluray/bdj/java/org/videolan/BDJClassLoader.java b/src/libbluray/bdj/java/org/videolan/BDJClassLoader.java -+index 733c3e5..2eb3844 100644 -+--- a/src/libbluray/bdj/java/org/videolan/BDJClassLoader.java -++++ b/src/libbluray/bdj/java/org/videolan/BDJClassLoader.java -+@@ -21,6 +21,7 @@ package org.videolan; -+ -+ import java.net.MalformedURLException; -+ -++import java.io.ByteArrayOutputStream; -+ import java.io.File; -+ import java.io.InputStream; -+ import java.io.IOException; -+@@ -126,7 +127,87 @@ public class BDJClassLoader extends URLClassLoader { -+ } -+ return c; -+ } -+- return super.loadClass(name); -++ -++ try { -++ return super.loadClass(name); -++ } catch (ClassNotFoundException e0) { -++ logger.error("ClassNotFoundException: " + name); -++ throw e0; -++ } catch (Error err) { -++ logger.error("FATAL: " + err); -++ throw err; -++ } -++ } -++ -++ private byte[] loadClassCode(String name) throws ClassNotFoundException { -++ String path = name.replace('.', '/').concat(".class"); -++ -++ URL res = super.findResource(path); -++ if (res == null) { -++ logger.error("loadClassCode(): resource for class " + name + "not found"); -++ throw new ClassNotFoundException(name); -++ } -++ -++ InputStream is = null; -++ ByteArrayOutputStream os = null; -++ try { -++ is = res.openStream(); -++ os = new ByteArrayOutputStream(); -++ byte[] buffer = new byte[0xffff]; -++ while (true) { -++ int r = is.read(buffer); -++ if (r == -1) break; -++ os.write(buffer, 0, r); -++ } -++ -++ return os.toByteArray(); -++ -++ } catch (Exception e) { -++ logger.error("loadClassCode(" + name + ") failed: " + e); -++ throw new ClassNotFoundException(name); -++ -++ } finally { -++ try { -++ if (is != null) -++ is.close(); -++ } catch (IOException ioe) { -++ } -++ try { -++ if (os != null) -++ os.close(); -++ } catch (IOException ioe) { -++ } -++ } -++ } -++ -++ protected Class findClass(String name) throws ClassNotFoundException { -++ try { -++ return super.findClass(name); -++ -++ } catch (ClassFormatError ce) { -++ -++ /* try to "fix" broken class file */ -++ /* if we got ClassFormatError, package was already created. */ -++ byte[] b = loadClassCode(name); -++ if (b == null) { -++ logger.error("loadClassCode(" + name + ") failed"); -++ /* this usually kills Xlet ... */ -++ throw ce; -++ } -++ try { -++ b = new BDJClassFileTransformer().transform(b, 0, b.length); -++ return defineClass(b, 0, b.length); -++ } catch (ThreadDeath td) { -++ throw td; -++ } catch (Throwable t) { -++ logger.error("Class rewriting failed: " + t); -++ throw new ClassNotFoundException(name); -++ } -++ -++ } catch (Error er) { -++ logger.error("Unexpected error: " + er + " " + Logger.dumpStack(er)); -++ throw er; -++ } -+ } -+ -+ public URL getResource(String name) { -+@@ -157,4 +238,6 @@ public class BDJClassLoader extends URLClassLoader { -+ } -+ -+ private String xletClass; -++ -++ private static final Logger logger = Logger.getLogger(BDJClassLoader.class.getName()); -+ } -+diff --git a/src/libbluray/bdj/java/org/videolan/BDJListeners.java b/src/libbluray/bdj/java/org/videolan/BDJListeners.java -+index 77acf4d..ba3a9c5 100644 -+--- a/src/libbluray/bdj/java/org/videolan/BDJListeners.java -++++ b/src/libbluray/bdj/java/org/videolan/BDJListeners.java -+@@ -56,6 +56,8 @@ import org.dvb.media.SubtitleListener; -+ import org.dvb.media.SubtitleNotAvailableEvent; -+ import org.dvb.media.SubtitleNotSelectedEvent; -+ import org.dvb.media.SubtitleSelectedEvent; -++import org.dvb.media.VideoFormatListener; -++import org.dvb.media.VideoFormatEvent; -+ -+ public class BDJListeners { -+ private LinkedList listeners = new LinkedList(); -+@@ -220,6 +222,9 @@ public class BDJListeners { -+ event instanceof SubtitleNotSelectedEvent || event instanceof SubtitleSelectedEvent) { -+ ((SubtitleListener)listener).subtitleStatusChanged((EventObject)event); -+ -++ } else if (event instanceof VideoFormatEvent) { -++ ((VideoFormatListener)listener).receiveVideoFormatEvent((VideoFormatEvent)event); -++ -+ } else if (event instanceof PSR102Status) { -+ ((StatusListener)listener).receive(((PSR102Status)event).value); -+ -+diff --git a/src/libbluray/bdj/java/org/videolan/BDJLoader.java b/src/libbluray/bdj/java/org/videolan/BDJLoader.java -+index 22bd37a..b2bcff3 100644 -+--- a/src/libbluray/bdj/java/org/videolan/BDJLoader.java -++++ b/src/libbluray/bdj/java/org/videolan/BDJLoader.java -+@@ -44,8 +44,60 @@ import org.videolan.media.content.PlayerManager; -+ -+ public class BDJLoader { -+ -++ private static class FontCacheAction extends BDJAction { -++ public FontCacheAction(InputStream is) { -++ this.fontPath = null; -++ this.is = is; -++ } -++ public FontCacheAction(String fontPath) { -++ this.fontPath = fontPath; -++ this.is = null; -++ } -++ -++ protected void doAction() { -++ try { -++ if (this.is != null) { -++ this.cacheFile = addFontImpl(is); -++ } else { -++ this.cacheFile = addFontImpl(fontPath); -++ } -++ } catch (RuntimeException e) { -++ this.exception = e; -++ } -++ } -++ -++ public File execute() { -++ BDJActionManager.getInstance().putCommand(this); -++ waitEnd(); -++ if (exception != null) { -++ throw exception; -++ } -++ return cacheFile; -++ } -++ -++ private final String fontPath; -++ private final InputStream is; -++ private File cacheFile = null; -++ private RuntimeException exception = null; -++ } -++ -+ /* called by org.dvb.ui.FontFactory */ -+ public static File addFont(InputStream is) { -++ if (BDJXletContext.getCurrentContext() == null) -++ return addFontImpl(is); -++ /* dispatch cache request to privileged thread */ -++ return new FontCacheAction(is).execute(); -++ } -++ -++ /* called by org.dvb.ui.FontFactory */ -++ public static File addFont(String fontFile) { -++ if (BDJXletContext.getCurrentContext() == null) -++ return addFontImpl(fontFile); -++ /* dispatch cache request to privileged thread */ -++ return new FontCacheAction(fontFile).execute(); -++ } -++ -++ private static File addFontImpl(InputStream is) { -+ VFSCache localCache = vfsCache; -+ if (localCache != null) { -+ return localCache.addFont(is); -+@@ -53,8 +105,7 @@ public class BDJLoader { -+ return null; -+ } -+ -+- /* called by org.dvb.ui.FontFactory */ -+- public static File addFont(String fontFile) { -++ private static File addFontImpl(String fontFile) { -+ VFSCache localCache = vfsCache; -+ if (localCache != null) { -+ return localCache.addFont(fontFile); -+@@ -134,11 +185,6 @@ public class BDJLoader { -+ throw new InvalidObjectException("bdjo not loaded"); -+ AppEntry[] appTable = bdjo.getAppTable(); -+ -+- // initialize AppCaches -+- if (vfsCache != null) { -+- vfsCache.add(bdjo.getAppCaches()); -+- } -+- -+ // reuse appProxys -+ BDJAppProxy[] proxys = new BDJAppProxy[appTable.length]; -+ AppsDatabase db = AppsDatabase.getAppsDatabase(); -+@@ -147,6 +193,15 @@ public class BDJLoader { -+ AppID id = (AppID)ids.nextElement(); -+ BDJAppProxy proxy = (BDJAppProxy)db.getAppProxy(id); -+ AppEntry entry = (AppEntry)db.getAppAttributes(id); -++ if (proxy == null) { -++ logger.error("AppsDatabase corrupted!"); -++ continue; -++ } -++ if (entry == null) { -++ logger.error("AppsDatabase corrupted!"); -++ proxy.release(); -++ continue; -++ } -+ for (int i = 0; i < appTable.length; i++) { -+ if (id.equals(appTable[i].getIdentifier()) && -+ entry.getInitialClass().equals(appTable[i].getInitialClass())) { -+@@ -155,7 +210,6 @@ public class BDJLoader { -+ proxy.stop(true); -+ } else { -+ logger.info("Keeping xlet " + appTable[i].getInitialClass()); -+- proxy.getXletContext().update(appTable[i], bdjo.getAppCaches()); -+ proxys[i] = proxy; -+ proxy = null; -+ } -+@@ -180,6 +234,11 @@ public class BDJLoader { -+ Libbluray.setUOMask(terminfo.getMenuCallMask(), terminfo.getTitleSearchMask()); -+ Libbluray.setKeyInterest(bdjo.getKeyInterestTable()); -+ -++ // initialize AppCaches -++ if (vfsCache != null) { -++ vfsCache.add(bdjo.getAppCaches()); -++ } -++ -+ // initialize appProxys -+ for (int i = 0; i < appTable.length; i++) { -+ if (proxys[i] == null) { -+@@ -196,6 +255,7 @@ public class BDJLoader { -+ } -+ logger.info("Loaded class: " + appTable[i].getInitialClass() + p + " from " + appTable[i].getBasePath() + ".jar"); -+ } else { -++ proxys[i].getXletContext().update(appTable[i], bdjo.getAppCaches()); -+ logger.info("Reused class: " + appTable[i].getInitialClass() + " from " + appTable[i].getBasePath() + ".jar"); -+ } -+ } -+@@ -206,6 +266,19 @@ public class BDJLoader { -+ // notify AppsDatabase -+ ((BDJAppsDatabase)BDJAppsDatabase.getAppsDatabase()).newDatabase(bdjo, proxys); -+ -++ // auto start playlist -++ try { -++ PlayListTable plt = bdjo.getAccessiblePlaylists(); -++ if ((plt != null) && (plt.isAutostartFirst())) { -++ logger.info("Auto-starting playlist"); -++ String[] pl = plt.getPlayLists(); -++ if (pl.length > 0) -++ Manager.createPlayer(new MediaLocator(new BDLocator("bd://PLAYLIST:" + pl[0]))).start(); -++ } -++ } catch (Exception e) { -++ logger.error("loadN(): autoplaylist failed: " + e + "\n" + Logger.dumpStack(e)); -++ } -++ -+ // now run all the xlets -+ for (int i = 0; i < appTable.length; i++) { -+ int code = appTable[i].getControlCode(); -+@@ -222,15 +295,6 @@ public class BDJLoader { -+ -+ logger.info("Finished initializing and starting xlets."); -+ -+- // auto start playlist -+- PlayListTable plt = bdjo.getAccessiblePlaylists(); -+- if ((plt != null) && (plt.isAutostartFirst())) { -+- logger.info("Auto-starting playlist"); -+- String[] pl = plt.getPlayLists(); -+- if (pl.length > 0) -+- Manager.createPlayer(new MediaLocator(new BDLocator("bd://PLAYLIST:" + pl[0]))).start(); -+- } -+- -+ return true; -+ -+ } catch (Throwable e) { -+diff --git a/src/libbluray/bdj/java/org/videolan/BDJSecurityManager.java b/src/libbluray/bdj/java/org/videolan/BDJSecurityManager.java -+index 38f8ac5..8a337ee 100644 -+--- a/src/libbluray/bdj/java/org/videolan/BDJSecurityManager.java -++++ b/src/libbluray/bdj/java/org/videolan/BDJSecurityManager.java -+@@ -76,6 +76,14 @@ final class BDJSecurityManager extends SecurityManager { -+ } -+ deny(perm); -+ } -++ -++ // work around bug in openjdk 7 / 8 -++ // sun.awt.AWTAutoShutdown.notifyThreadBusy is missing doPrivileged() -++ // (fixed in jdk9 / http://hg.openjdk.java.net/jdk9/client/jdk/rev/5b613a3c04be ) -++ if (classDepth("sun.awt.AWTAutoShutdown") > 0) { -++ return; -++ } -++ -+ if (perm.implies(new RuntimePermission("modifyThreadGroup"))) { -+ /* do check here (no need to log failures) */ -+ super.checkPermission(perm); -+@@ -119,6 +127,10 @@ final class BDJSecurityManager extends SecurityManager { -+ return; -+ } -+ } -++ if (perm.getActions().contains("write")) { -++ /* write permissions are handled in checkWrite() */ -++ deny(perm); -++ } -+ } -+ -+ /* Networking */ -+@@ -180,6 +192,10 @@ final class BDJSecurityManager extends SecurityManager { -+ throw new SecurityException("exit denied"); -+ } -+ -++ public void checkSystemClipboardAccess() { -++ throw new SecurityException("clipboard access denied"); -++ } -++ -+ /* -+ * file read access -+ */ -+diff --git a/src/libbluray/bdj/java/org/videolan/BDJThreadGroup.java b/src/libbluray/bdj/java/org/videolan/BDJThreadGroup.java -+index f4bc1dc..4943a7e 100644 -+--- a/src/libbluray/bdj/java/org/videolan/BDJThreadGroup.java -++++ b/src/libbluray/bdj/java/org/videolan/BDJThreadGroup.java -+@@ -20,9 +20,9 @@ -+ -+ package org.videolan; -+ -+-public class BDJThreadGroup extends ThreadGroup { -++class BDJThreadGroup extends ThreadGroup { -+ -+- public BDJThreadGroup(String name, BDJXletContext context) { -++ protected BDJThreadGroup(String name, BDJXletContext context) { -+ super(name); -+ this.context = context; -+ } -+@@ -45,15 +45,11 @@ public class BDJThreadGroup extends ThreadGroup { -+ } -+ } -+ -+- public BDJXletContext getContext() { -++ protected BDJXletContext getContext() { -+ return context; -+ } -+ -+- public void setContext(BDJXletContext context) { -+- this.context = context; -+- } -+- -+- public boolean waitForShutdown(int timeout, int maxThreads) { -++ protected boolean waitForShutdown(int timeout, int maxThreads) { -+ -+ if (parentOf(Thread.currentThread().getThreadGroup()) && maxThreads < 1) { -+ logger.error("Current Thread is contained within ThreadGroup to be disposed."); -+@@ -94,8 +90,6 @@ public class BDJThreadGroup extends ThreadGroup { -+ } catch (IllegalThreadStateException e) { -+ logger.error("ThreadGroup destroy failed: " + e); -+ } -+- -+- context = null; -+ } -+ -+ public void dumpThreads() { -+@@ -115,6 +109,6 @@ public class BDJThreadGroup extends ThreadGroup { -+ } -+ } -+ -+- private BDJXletContext context; -++ private final BDJXletContext context; -+ private static final Logger logger = Logger.getLogger(BDJThreadGroup.class.getName()); -+ } -+diff --git a/src/libbluray/bdj/java/org/videolan/BDJUtil.java b/src/libbluray/bdj/java/org/videolan/BDJUtil.java -+index 507c2e7..cc17992 100644 -+--- a/src/libbluray/bdj/java/org/videolan/BDJUtil.java -++++ b/src/libbluray/bdj/java/org/videolan/BDJUtil.java -+@@ -25,20 +25,31 @@ public class BDJUtil { -+ /** -+ * Make a five digit zero padded string based on an integer -+ * Ex. integer 1 -> string "00001" -+- * -++ * -+ * @param id -+ * @return -+ */ -+- public static String makeFiveDigitStr(int id) -++ public static String makeFiveDigitStr(int id) -+ { -++ if (id < 0 || id > 99999) { -++ System.err.println("Invalid ID: " + id); -++ throw new IllegalArgumentException("Invalid ID " + id); -++ } -++ String s = "" + id; -++ while (s.length() < 5) { -++ s = "0" + s; -++ } -++ return s; -++ /* -+ DecimalFormat fmt = new DecimalFormat(); -+ fmt.setMaximumIntegerDigits(5); -+ fmt.setMinimumIntegerDigits(5); -+ fmt.setGroupingUsed(false); -+- -++ -+ return fmt.format(id); -++ */ -+ } -+- -++ -+ /** -+ * Make a path based on the disc root to an absolute path based on the filesystem of the computer -+ * Ex. /BDMV/JAR/00000.jar -> /bluray/disc/mount/point/BDMV/JAR/00000.jar -+@@ -47,6 +58,11 @@ public class BDJUtil { -+ */ -+ public static String discRootToFilesystem(String path) -+ { -+- return System.getProperty("bluray.vfs.root") + path; -++ String vfsRoot = System.getProperty("bluray.vfs.root"); -++ if (vfsRoot == null) { -++ System.err.println("discRootToFilesystem(): disc root not set !"); -++ return path; -++ } -++ return vfsRoot + path; -+ } -+ } -+diff --git a/src/libbluray/bdj/java/org/videolan/BDJXletContext.java b/src/libbluray/bdj/java/org/videolan/BDJXletContext.java -+index ae5b3a0..8ee818a 100644 -+--- a/src/libbluray/bdj/java/org/videolan/BDJXletContext.java -++++ b/src/libbluray/bdj/java/org/videolan/BDJXletContext.java -+@@ -70,7 +70,12 @@ public class BDJXletContext implements javax.tv.xlet.XletContext, javax.microedi -+ try { -+ int homeJarID = Integer.parseInt(home); -+ long time = System.currentTimeMillis(); -+- homeMountPoint = MountManager.mount(homeJarID, false) + java.io.File.separator; -++ homeMountPoint = MountManager.mount(homeJarID, false); -++ if (homeMountPoint == null) { -++ logger.error("Failed mounting " + home + ".jar"); -++ } else { -++ homeMountPoint = homeMountPoint + java.io.File.separator; -++ } -+ time = System.currentTimeMillis() - time; -+ logger.info("Mounted Xlet home directory from " + home + ".jar " + -+ "to " + homeMountPoint + "(" + time + "ms)"); -+@@ -80,6 +85,8 @@ public class BDJXletContext implements javax.tv.xlet.XletContext, javax.microedi -+ } -+ -+ public String getXletHome() { -++ if (homeMountPoint == null) -++ logger.error("Home directory not mounted!"); -+ return homeMountPoint; -+ } -+ -+@@ -102,6 +109,8 @@ public class BDJXletContext implements javax.tv.xlet.XletContext, javax.microedi -+ return Integer.toHexString(appid.getAID()); -+ else if (key.equals("org.dvb.application.appid")) -+ return appid; -++ -++ logger.error("unhandled getXletProperty(" + key + ")"); -+ return null; -+ } -+ -+diff --git a/src/libbluray/bdj/java/org/videolan/IxcRegistryImpl.java b/src/libbluray/bdj/java/org/videolan/IxcRegistryImpl.java -+index a9fe28d..bae986f 100644 -+--- a/src/libbluray/bdj/java/org/videolan/IxcRegistryImpl.java -++++ b/src/libbluray/bdj/java/org/videolan/IxcRegistryImpl.java -+@@ -260,7 +260,7 @@ public class IxcRegistryImpl { -+ return result; -+ } -+ -+- public class RemoteMethod implements Runnable -++ private class RemoteMethod implements Runnable -+ { -+ final BDJXletContext calleeContext; -+ final BDJXletContext callerContext; -+@@ -276,9 +276,11 @@ public class IxcRegistryImpl { -+ callerContext = BDJXletContext.getCurrentContext(); -+ if (callerContext == null) { -+ logger.error("caller context is null"); -++ throw new RemoteException("no caller context"); -+ } -+ if (context == null) { -+ logger.error("callee context is null"); -++ throw new RemoteException("no callee context"); -+ } -+ calleeContext = context; -+ -+@@ -426,6 +428,18 @@ public class IxcRegistryImpl { -+ throw new IllegalArgumentException("xc not current BDJXletContext"); -+ } -+ -++ if ("/7fff7669/4050/Messenger".equals(path)) { -++ /* known discs: -++ - Terminator Salvation -++ */ -++ try { -++ logger.error("Enabling Ixc delay hack for " + path); -++ Thread.sleep(200L); -++ } catch (InterruptedException ie) { -++ ie.printStackTrace(); -++ } -++ } -++ -+ WrappedRemoteObj wrappedObj = null; -+ synchronized (remoteObjects) { -+ if (!remoteObjects.containsKey(path)) { -+@@ -438,7 +452,7 @@ public class IxcRegistryImpl { -+ } -+ Object remoteObj = wrapOrCopy(wrappedObj, wrappedObj.context, (BDJXletContext)xc); -+ -+- Debug("IxcRegistry.lookup(" + path + ") => " + remoteObj); -++ Debug("IxcRegistry.lookup(" + path + ") => OK"); -+ -+ return (Remote)remoteObj; -+ } -+diff --git a/src/libbluray/bdj/java/org/videolan/Libbluray.java b/src/libbluray/bdj/java/org/videolan/Libbluray.java -+index 41af18f..6a97ad7 100644 -+--- a/src/libbluray/bdj/java/org/videolan/Libbluray.java -++++ b/src/libbluray/bdj/java/org/videolan/Libbluray.java -+@@ -24,6 +24,8 @@ import java.awt.BDFontMetrics; -+ import java.awt.BDToolkit; -+ import java.awt.event.KeyEvent; -+ import java.io.File; -++import java.util.HashMap; -++import java.util.Map; -+ import java.util.Vector; -+ -+ import javax.media.PackageManager; -+@@ -50,14 +52,7 @@ public class Libbluray { -+ -+ /* hook system properties: make "user.dir" point to current Xlet home directory */ -+ -+- private static boolean propertiesHooked = false; -+- -+ private static void hookProperties() { -+- if (propertiesHooked) { -+- return; -+- } -+- propertiesHooked = true; -+- -+ java.util.Properties p = new java.util.Properties(System.getProperties()) { -+ public String getProperty(String key) { -+ if (key.equals("user.dir")) { -+@@ -65,6 +60,7 @@ public class Libbluray { -+ if (ctx != null) { -+ return ctx.getXletHome(); -+ } -++ System.err.println("getProperty(user.dir): no context ! " + Logger.dumpStack()); -+ } -+ return super.getProperty(key); -+ } -+@@ -72,6 +68,28 @@ public class Libbluray { -+ System.setProperties(p); -+ } -+ -++ private static boolean initOnce = false; -++ private static void initOnce() { -++ if (initOnce) { -++ return; -++ } -++ initOnce = true; -++ -++ /* hook system properties (provide Xlet-specific user.dir) */ -++ try { -++ hookProperties(); -++ } catch (Throwable t) { -++ System.err.println("hookProperties() failed: " + t); -++ } -++ -++ /* hook sockets (limit network connections) */ -++ try { -++ BDJSocketFactory.init(); -++ } catch (Throwable t) { -++ System.err.println("Hooking socket factory failed: " + t + "\n" + Logger.dumpStack(t)); -++ } -++ } -++ -+ private static String canonicalize(String path, boolean create) { -+ try { -+ File dir = new File(path); -+@@ -89,7 +107,7 @@ public class Libbluray { -+ private static void init(long nativePointer, String discID, String discRoot, -+ String persistentRoot, String budaRoot) { -+ -+- hookProperties(); -++ initOnce(); -+ -+ /* set up directories */ -+ persistentRoot = canonicalize(persistentRoot, true); -+@@ -185,8 +203,6 @@ public class Libbluray { -+ -+ System.setProperty("bluray.network.connected", "YES"); -+ -+- BDJSocketFactory.init(); -+- -+ try { -+ System.setSecurityManager(new BDJSecurityManager(discRoot, persistentRoot, budaRoot)); -+ } catch (Exception ex) { -+@@ -228,6 +244,7 @@ public class Libbluray { -+ } -+ nativePointer = 0; -+ titleInfos = null; -++ bdjoFiles = null; -+ } -+ -+ /* -+@@ -296,6 +313,10 @@ public class Libbluray { -+ * Disc data -+ */ -+ -++ /* cache parsed .bdjo files */ -++ private static Map bdjoFiles = null; -++ private static Object bdjoFilesLock = new Object(); -++ -+ public static byte[] getAacsData(int type) { -+ return getAacsDataN(nativePointer, type); -+ } -+@@ -305,7 +326,23 @@ public class Libbluray { -+ } -+ -+ public static Bdjo getBdjo(String name) { -+- return getBdjoN(nativePointer, name + ".bdjo"); -++ Bdjo bdjo; -++ synchronized (bdjoFilesLock) { -++ if (bdjoFiles == null) { -++ bdjoFiles = new HashMap(); -++ } else { -++ bdjo = (Bdjo)bdjoFiles.get(name); -++ if (bdjo != null) { -++ return bdjo; -++ } -++ } -++ -++ bdjo = getBdjoN(nativePointer, name + ".bdjo"); -++ if (bdjo != null) { -++ bdjoFiles.put(name, bdjo); -++ } -++ return bdjo; -++ } -+ } -+ -+ public static String[] listBdFiles(String path, boolean onlyBdRom) { -+diff --git a/src/libbluray/bdj/java/org/videolan/MountManager.java b/src/libbluray/bdj/java/org/videolan/MountManager.java -+index 83d6870..6f6fd52 100644 -+--- a/src/libbluray/bdj/java/org/videolan/MountManager.java -++++ b/src/libbluray/bdj/java/org/videolan/MountManager.java -+@@ -185,6 +185,7 @@ public class MountManager { -+ new PrivilegedAction() { -+ public Object run() { -+ if (mountPoint.decRefCount() < 1) { -++ logger.error("Removing JAR " + id + " from mount cache"); -+ mountPoints.remove(id); -+ } -+ return null; -+@@ -221,7 +222,7 @@ public class MountManager { -+ if (mountPoint != null) { -+ return mountPoint.getMountPoint(); -+ } else { -+- logger.info("JAR " + jarId + " not mounted"); -++ logger.error("JAR " + jarId + " not mounted"); -+ } -+ return null; -+ } -+@@ -247,6 +248,7 @@ public class MountManager { -+ if (dir != null) { -+ return dir.getAbsolutePath(); -+ } -++ logger.error("getMountPoint(): already unmounted !"); -+ return null; -+ } -+ -+@@ -274,8 +276,8 @@ public class MountManager { -+ return classFiles; -+ } -+ -+- public boolean setClassFiles() { -+- return classFiles == true; -++ public void setClassFiles() { -++ classFiles = true; -+ } -+ -+ private File dir; -+diff --git a/src/libbluray/bdj/java/org/videolan/TitleInfo.java b/src/libbluray/bdj/java/org/videolan/TitleInfo.java -+index 1c1075b..10dc62a 100644 -+--- a/src/libbluray/bdj/java/org/videolan/TitleInfo.java -++++ b/src/libbluray/bdj/java/org/videolan/TitleInfo.java -+@@ -24,7 +24,7 @@ public class TitleInfo { -+ this.objType = objType; -+ this.playbackType = playbackType; -+ if (objType == OBJ_TYPE_BDJ) -+- this.bdjoName = (new java.text.DecimalFormat("00000")).format(idRef); -++ this.bdjoName = (BDJUtil.makeFiveDigitStr(idRef)); -+ else -+ this.hdmvOID = idRef; -+ } -+diff --git a/src/libbluray/bdj/java/org/videolan/VFSCache.java b/src/libbluray/bdj/java/org/videolan/VFSCache.java -+index 2bcfbe9..22fe1f0 100644 -+--- a/src/libbluray/bdj/java/org/videolan/VFSCache.java -++++ b/src/libbluray/bdj/java/org/videolan/VFSCache.java -+@@ -270,16 +270,19 @@ class VFSCache { -+ accessFileSynced(absPath); -+ } -+ -+- protected synchronized void accessFileSynced(String absPath) { -++ private synchronized void accessFileSynced(String absPath) { -+ -+ if (inAccessFile) { -+ /* avoid recursion from SecurityManager checks */ -+ return; -+ } -+ -+- inAccessFile = true; -+- accessFileImp(absPath); -+- inAccessFile = false; -++ try { -++ inAccessFile = true; -++ accessFileImp(absPath); -++ } finally { -++ inAccessFile = false; -++ } -+ } -+ -+ private void accessFileImp(String absPath) { -+@@ -297,7 +300,7 @@ class VFSCache { -+ } -+ -+ /* do not cache .m2ts streams */ -+- if (relPath.startsWith("BDMV" + File.separator + "STREAM" + File.separator)) { -++ if (relPath.startsWith(streamDir)) { -+ return; -+ } -+ -+@@ -352,6 +355,7 @@ class VFSCache { -+ -+ private static final String jarDir = "BDMV" + File.separator + "JAR" + File.separator; -+ private static final String fontDir = "BDMV" + File.separator + "AUXDATA" + File.separator; -++ private static final String streamDir = "BDMV" + File.separator + "STREAM" + File.separator; -+ -+ private static final Logger logger = Logger.getLogger(VFSCache.class.getName()); -+ } -+diff --git a/src/libbluray/bdj/java/org/videolan/media/content/BDHandler.java b/src/libbluray/bdj/java/org/videolan/media/content/BDHandler.java -+index 3d43579..92269f1 100644 -+--- a/src/libbluray/bdj/java/org/videolan/media/content/BDHandler.java -++++ b/src/libbluray/bdj/java/org/videolan/media/content/BDHandler.java -+@@ -67,10 +67,13 @@ public abstract class BDHandler implements Player, ServiceContentHandler { -+ -+ public BDHandler() { -+ ownerContext = BDJXletContext.getCurrentContext(); -+- -+- PlayerAction action = new PlayerAction(this, PlayerAction.ACTION_INIT, null); -+- BDJActionManager.getInstance().putCommand(action); -+- action.waitEnd(); -++ if (ownerContext == null) { -++ doInitAction(); -++ } else { -++ PlayerAction action = new PlayerAction(this, PlayerAction.ACTION_INIT, null); -++ BDJActionManager.getInstance().putCommand(action); -++ action.waitEnd(); -++ } -+ } -+ -+ private void doInitAction() { -+diff --git a/src/libbluray/bdj/java/org/videolan/media/content/PlayerManager.java b/src/libbluray/bdj/java/org/videolan/media/content/PlayerManager.java -+index cc06e84..d45358b 100644 -+--- a/src/libbluray/bdj/java/org/videolan/media/content/PlayerManager.java -++++ b/src/libbluray/bdj/java/org/videolan/media/content/PlayerManager.java -+@@ -19,6 +19,7 @@ -+ package org.videolan.media.content; -+ -+ import java.util.ArrayList; -++import org.videolan.Logger; -+ -+ public class PlayerManager { -+ -+@@ -81,7 +82,7 @@ public class PlayerManager { -+ return; -+ } -+ -+- System.err.println("unknown player type: " + player.getClass().getName()); -++ logger.error("unknown player type: " + player.getClass().getName()); -+ } -+ -+ protected boolean allocateResource(BDHandler player) { -+@@ -91,6 +92,9 @@ public class PlayerManager { -+ } -+ synchronized (playlistPlayerLock) { -+ if (playlistPlayer != null && player != playlistPlayer) { -++ -++ logger.info("allocateResource(): Stopping old playlist player"); -++ -+ playlistPlayer.stop(); -+ playlistPlayer.deallocate(); -+ } -+@@ -108,7 +112,7 @@ public class PlayerManager { -+ return true; -+ } -+ -+- System.err.println("unknown player type: " + player.getClass().getName()); -++ logger.error("allocateResource(): unknown player type: " + player.getClass().getName()); -+ return false; -+ } -+ -+@@ -153,4 +157,6 @@ public class PlayerManager { -+ } -+ } -+ } -++ -++ private static final Logger logger = Logger.getLogger(PlayerManager.class.getName()); -+ } -+diff --git a/src/libbluray/bdj/java/org/videolan/media/content/playlist/BackgroundVideoPresentationControlImpl.java b/src/libbluray/bdj/java/org/videolan/media/content/playlist/BackgroundVideoPresentationControlImpl.java -+index 05ae554..21f6de5 100644 -+--- a/src/libbluray/bdj/java/org/videolan/media/content/playlist/BackgroundVideoPresentationControlImpl.java -++++ b/src/libbluray/bdj/java/org/videolan/media/content/playlist/BackgroundVideoPresentationControlImpl.java -+@@ -53,6 +53,8 @@ public class BackgroundVideoPresentationControlImpl extends VideoControl -+ } -+ -+ public boolean setVideoTransformation(VideoTransformation transform) { -++ if (transform == null) -++ return false; -+ setClipRegion(transform.getClipRegion()); -+ HScreenPoint pos = transform.getVideoPosition(); -+ float[] scales = transform.getScalingFactors(); -+@@ -99,40 +101,40 @@ public class BackgroundVideoPresentationControlImpl extends VideoControl -+ return new AWTVideoSize( -+ new Rectangle(vd.width, vd.height), -+ new Rectangle(sd.width, sd.height)); -+- } -++ } -+ -+- public Dimension getSourceVideoSize() { -+- return getVideoSize(); -+- } -++ public Dimension getSourceVideoSize() { -++ return getVideoSize(); -++ } -+ -+- public boolean setSize(AWTVideoSize size) { -+- setClipRegion(size.getSource()); -+- setVideoArea(getNormalizedRectangle(getScreenSize(), size.getDestination())); -+- return true; -+- } -++ public boolean setSize(AWTVideoSize size) { -++ setClipRegion(size.getSource()); -++ setVideoArea(getNormalizedRectangle(getScreenSize(), size.getDestination())); -++ return true; -++ } -+ -+- public AWTVideoSize checkSize(AWTVideoSize size) { -+- Dimension vd = getInputVideoSize(); -+- Rectangle sr = size.getSource(); -+- if (sr.x < 0) -++ public AWTVideoSize checkSize(AWTVideoSize size) { -++ Dimension vd = getInputVideoSize(); -++ Rectangle sr = size.getSource(); -++ if (sr.x < 0) -++ sr.x = 0; -++ if ((sr.x + sr.width) > vd.width) { -++ sr.width = vd.width - sr.x; -++ if (sr.width <= 0) { -+ sr.x = 0; -+- if ((sr.x + sr.width) > vd.width) { -+- sr.width = vd.width - sr.x; -+- if (sr.width <= 0) { -+- sr.x = 0; -+- sr.width = 0; -+- } -++ sr.width = 0; -+ } -+- if (sr.y < 0) -++ } -++ if (sr.y < 0) -++ sr.y = 0; -++ if ((sr.y + sr.height) > vd.height) { -++ sr.height = vd.height - sr.y; -++ if (sr.height <= 0) { -+ sr.y = 0; -+- if ((sr.y + sr.height) > vd.height) { -+- sr.height = vd.height - sr.y; -+- if (sr.height <= 0) { -+- sr.y = 0; -+- sr.height = 0; -+- } -++ sr.height = 0; -+ } -+- Rectangle dr = size.getDestination(); -+- return new AWTVideoSize(sr, dr); -+ } -++ Rectangle dr = size.getDestination(); -++ return new AWTVideoSize(sr, dr); -++ } -+ } -+diff --git a/src/libbluray/bdj/java/org/videolan/media/content/playlist/Handler.java b/src/libbluray/bdj/java/org/videolan/media/content/playlist/Handler.java -+index 7e52949..8728628 100644 -+--- a/src/libbluray/bdj/java/org/videolan/media/content/playlist/Handler.java -++++ b/src/libbluray/bdj/java/org/videolan/media/content/playlist/Handler.java -+@@ -72,6 +72,7 @@ public class Handler extends BDHandler { -+ synchronized (this) { -+ try { -+ locator = new BDLocator(source.getLocator().toExternalForm()); -++ currentLocator = null; -+ } catch (org.davic.net.InvalidLocatorException e) { -+ throw new IncompatibleSourceException(); -+ } -+@@ -294,7 +295,11 @@ public class Handler extends BDHandler { -+ -+ protected void doEndOfMediaReached(int playlist) { -+ synchronized (this) { -+- if (locator == null || locator.getPlayListId() != playlist) { -++ if (locator == null) { -++ System.err.println("endOfMedia(" + playlist + ") ignored: no current locator"); -++ return; -++ } -++ if (locator.getPlayListId() != playlist) { -+ System.err.println("endOfMedia ignored: playlist does not match (" + playlist + " != " + locator.getPlayListId()); -+ return; -+ } -+@@ -336,6 +341,7 @@ public class Handler extends BDHandler { -+ if (pi == null) -+ throw new InvalidPlayListException(); -+ this.locator = locator; -++ this.currentLocator = null; -+ baseMediaTime = 0; -+ if (state == Prefetched) -+ doPrefetch(); -+diff --git a/src/libbluray/bdj/java/org/videolan/media/content/video/dvb/mpeg/drip/BackgroundVideoPresentationControlImpl.java b/src/libbluray/bdj/java/org/videolan/media/content/video/dvb/mpeg/drip/BackgroundVideoPresentationControlImpl.java -+index 3596def..377aacc 100644 -+--- a/src/libbluray/bdj/java/org/videolan/media/content/video/dvb/mpeg/drip/BackgroundVideoPresentationControlImpl.java -++++ b/src/libbluray/bdj/java/org/videolan/media/content/video/dvb/mpeg/drip/BackgroundVideoPresentationControlImpl.java -+@@ -100,23 +100,23 @@ public class BackgroundVideoPresentationControlImpl extends VideoControl -+ Rectangle sr = size.getSource(); -+ if (sr.x < 0) -+ sr.x = 0; -+- if ((sr.x + sr.width) > vd.width) { -+- sr.width = vd.width - sr.x; -+- if (sr.width <= 0) { -+- sr.x = 0; -+- sr.width = 0; -+- } -++ if ((sr.x + sr.width) > vd.width) { -++ sr.width = vd.width - sr.x; -++ if (sr.width <= 0) { -++ sr.x = 0; -++ sr.width = 0; -+ } -+- if (sr.y < 0) -++ } -++ if (sr.y < 0) -++ sr.y = 0; -++ if ((sr.y + sr.height) > vd.height) { -++ sr.height = vd.height - sr.y; -++ if (sr.height <= 0) { -+ sr.y = 0; -+- if ((sr.y + sr.height) > vd.height) { -+- sr.height = vd.height - sr.y; -+- if (sr.height <= 0) { -+- sr.y = 0; -+- sr.height = 0; -+- } -++ sr.height = 0; -+ } -+- Rectangle dr = size.getDestination(); -+- return new AWTVideoSize(sr, dr); -++ } -++ Rectangle dr = size.getDestination(); -++ return new AWTVideoSize(sr, dr); -+ } -+ } -+diff --git a/src/libbluray/bdj/native/java_awt_BDFontMetrics.c b/src/libbluray/bdj/native/java_awt_BDFontMetrics.c -+index 3bbd3c3..f84a382 100644 -+--- a/src/libbluray/bdj/native/java_awt_BDFontMetrics.c -++++ b/src/libbluray/bdj/native/java_awt_BDFontMetrics.c -+@@ -135,7 +135,10 @@ static char *_win32_resolve_font(const char *family, int style) -+ -+ memset(&lf, 0, sizeof(lf)); -+ lf.lfCharSet = DEFAULT_CHARSET; -+- MultiByteToWideChar(CP_UTF8, 0, family, -1, lf.lfFaceName, sizeof(lf.lfFaceName)); -++ int length = MultiByteToWideChar(CP_UTF8, 0, family, -1, lf.lfFaceName, LF_FACESIZE); -++ if (!length) { -++ return NULL; -++ } -+ -+ hDC = GetDC(NULL); -+ EnumFontFamiliesExW(hDC, &lf, (FONTENUMPROCW)&EnumFontCallbackW, (LPARAM)&data, 0); +diff --git a/src/libbluray/bdnav/clpi_parse.c b/src/libbluray/bdnav/clpi_parse.c -+index 365ec0f..f0826de 100644 ++index 394347e..39bbcef 100644 +--- a/src/libbluray/bdnav/clpi_parse.c ++++ b/src/libbluray/bdnav/clpi_parse.c +@@ -39,6 +39,7 @@ @@ -76902,244 +50932,8 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + + char sig[9]; + char expect[9]; -+@@ -223,7 +225,7 @@ _parse_sequence(BITSTREAM *bits, CLPI_CL *cl) -+ cl->sequence.num_atc_seq = bs_read(bits, 8); -+ -+ CLPI_ATC_SEQ *atc_seq; -+- atc_seq = malloc(cl->sequence.num_atc_seq * sizeof(CLPI_ATC_SEQ)); -++ atc_seq = calloc(cl->sequence.num_atc_seq, sizeof(CLPI_ATC_SEQ)); -+ cl->sequence.atc_seq = atc_seq; -+ for (ii = 0; ii < cl->sequence.num_atc_seq; ii++) { -+ atc_seq[ii].spn_atc_start = bs_read(bits, 32); -+@@ -254,7 +256,7 @@ _parse_program(BITSTREAM *bits, CLPI_PROG_INFO *program) -+ program->num_prog = bs_read(bits, 8); -+ -+ CLPI_PROG *progs; -+- progs = malloc(program->num_prog * sizeof(CLPI_PROG)); -++ progs = calloc(program->num_prog, sizeof(CLPI_PROG)); -+ program->progs = progs; -+ for (ii = 0; ii < program->num_prog; ii++) { -+ progs[ii].spn_program_sequence_start = bs_read(bits, 32); -+@@ -263,7 +265,7 @@ _parse_program(BITSTREAM *bits, CLPI_PROG_INFO *program) -+ progs[ii].num_groups = bs_read(bits, 8); -+ -+ CLPI_PROG_STREAM *ps; -+- ps = malloc(progs[ii].num_streams * sizeof(CLPI_PROG_STREAM)); -++ ps = calloc(progs[ii].num_streams, sizeof(CLPI_PROG_STREAM)); -+ progs[ii].streams = ps; -+ for (jj = 0; jj < progs[ii].num_streams; jj++) { -+ ps[jj].pid = bs_read(bits, 16); -+@@ -335,7 +337,7 @@ _parse_cpi(BITSTREAM *bits, CLPI_CPI *cpi) -+ cpi->num_stream_pid = bs_read(bits, 8); -+ -+ CLPI_EP_MAP_ENTRY *entry; -+- entry = malloc(cpi->num_stream_pid * sizeof(CLPI_EP_MAP_ENTRY)); -++ entry = calloc(cpi->num_stream_pid, sizeof(CLPI_EP_MAP_ENTRY)); -+ cpi->entry = entry; -+ for (ii = 0; ii < cpi->num_stream_pid; ii++) { -+ entry[ii].pid = bs_read(bits, 16); -+@@ -622,12 +624,12 @@ _clean_program(CLPI_PROG_INFO *p) -+ { -+ int ii; -+ -+- for (ii = 0; ii < p->num_prog; ii++) { -+- if (p->progs[ii].streams != NULL) { -++ if (p && p->progs) { -++ for (ii = 0; ii < p->num_prog; ii++) { -+ X_FREE(p->progs[ii].streams); -+ } -++ X_FREE(p->progs); -+ } -+- X_FREE(p->progs); -+ } -+ -+ static void -+@@ -635,15 +637,13 @@ _clean_cpi(CLPI_CPI *cpi) -+ { -+ int ii; -+ -+- for (ii = 0; ii < cpi->num_stream_pid; ii++) { -+- if (cpi->entry[ii].coarse != NULL) { -++ if (cpi && cpi->entry) { -++ for (ii = 0; ii < cpi->num_stream_pid; ii++) { -+ X_FREE(cpi->entry[ii].coarse); -+- } -+- if (cpi->entry[ii].fine != NULL) { -+ X_FREE(cpi->entry[ii].fine); -+ } -++ X_FREE(cpi->entry); -+ } -+- X_FREE(cpi->entry); -+ } -+ -+ void -+@@ -654,15 +654,12 @@ clpi_free(CLPI_CL *cl) -+ if (cl == NULL) { -+ return; -+ } -+- if (cl->clip.atc_delta != NULL) { -+- X_FREE(cl->clip.atc_delta); -+- } -+- for (ii = 0; ii < cl->sequence.num_atc_seq; ii++) { -+- if (cl->sequence.atc_seq[ii].stc_seq != NULL) { -++ X_FREE(cl->clip.atc_delta); -++ if (cl->sequence.atc_seq) { -++ for (ii = 0; ii < cl->sequence.num_atc_seq; ii++) { -+ X_FREE(cl->sequence.atc_seq[ii].stc_seq); -+ } -+- } -+- if (cl->sequence.atc_seq != NULL) { -++ -+ X_FREE(cl->sequence.atc_seq); -+ } -+ -+@@ -796,7 +793,7 @@ clpi_copy(const CLPI_CL* src_cl) -+ } -+ -+ dest_cl->sequence.num_atc_seq = src_cl->sequence.num_atc_seq; -+- dest_cl->sequence.atc_seq = malloc(src_cl->sequence.num_atc_seq * sizeof(CLPI_ATC_SEQ)); -++ dest_cl->sequence.atc_seq = calloc(src_cl->sequence.num_atc_seq, sizeof(CLPI_ATC_SEQ)); -+ for (ii = 0; ii < src_cl->sequence.num_atc_seq; ii++) { -+ dest_cl->sequence.atc_seq[ii].spn_atc_start = src_cl->sequence.atc_seq[ii].spn_atc_start; -+ dest_cl->sequence.atc_seq[ii].offset_stc_id = src_cl->sequence.atc_seq[ii].offset_stc_id; -+@@ -811,7 +808,7 @@ clpi_copy(const CLPI_CL* src_cl) -+ } -+ -+ dest_cl->program.num_prog = src_cl->program.num_prog; -+- dest_cl->program.progs = malloc(src_cl->program.num_prog * sizeof(CLPI_PROG)); -++ dest_cl->program.progs = calloc(src_cl->program.num_prog, sizeof(CLPI_PROG)); -+ for (ii = 0; ii < src_cl->program.num_prog; ii++) { -+ dest_cl->program.progs[ii].spn_program_sequence_start = src_cl->program.progs[ii].spn_program_sequence_start; -+ dest_cl->program.progs[ii].program_map_pid = src_cl->program.progs[ii].program_map_pid; -+@@ -831,7 +828,7 @@ clpi_copy(const CLPI_CL* src_cl) -+ } -+ -+ dest_cl->cpi.num_stream_pid = src_cl->cpi.num_stream_pid; -+- dest_cl->cpi.entry = malloc(src_cl->cpi.num_stream_pid * sizeof(CLPI_EP_MAP_ENTRY)); -++ dest_cl->cpi.entry = calloc(src_cl->cpi.num_stream_pid, sizeof(CLPI_EP_MAP_ENTRY)); -+ for (ii = 0; ii < dest_cl->cpi.num_stream_pid; ii++) { -+ dest_cl->cpi.entry[ii].pid = src_cl->cpi.entry[ii].pid; -+ dest_cl->cpi.entry[ii].ep_stream_type = src_cl->cpi.entry[ii].ep_stream_type; -+diff --git a/src/libbluray/bdnav/index_parse.c b/src/libbluray/bdnav/index_parse.c -+index 6c07ba1..64dc5e3 100644 -+--- a/src/libbluray/bdnav/index_parse.c -++++ b/src/libbluray/bdnav/index_parse.c -+@@ -103,8 +103,16 @@ static int _parse_index(BITSTREAM *bs, INDX_ROOT *index) -+ } -+ -+ index->num_titles = bs_read(bs, 16); -++ if (!index->num_titles) { -++ BD_DEBUG(DBG_CRIT, "empty index\n"); -++ return 0; -++ } -+ -+ index->titles = calloc(index->num_titles, sizeof(INDX_TITLE)); -++ if (!index->titles) { -++ BD_DEBUG(DBG_CRIT, "out of memory\n"); -++ return 0; -++ } -+ -+ for (i = 0; i < index->num_titles; i++) { -+ -+diff --git a/src/libbluray/bdnav/meta_parse.c b/src/libbluray/bdnav/meta_parse.c -+index 50b8c75..a9a7edc 100644 -+--- a/src/libbluray/bdnav/meta_parse.c -++++ b/src/libbluray/bdnav/meta_parse.c -+@@ -81,29 +81,35 @@ static void _parseManifestNode(xmlNode * a_node, META_DL *disclib) -+ } -+ else if (xmlStrEqual(cur_node->parent->name, BAD_CAST_CONST "tableOfContents")) { -+ if (xmlStrEqual(cur_node->name, BAD_CAST_CONST "titleName") && (tmp = xmlGetProp(cur_node, BAD_CAST_CONST "titleNumber"))) { -+- int i = disclib->toc_count; -+- disclib->toc_count++; -+- disclib->toc_entries = realloc(disclib->toc_entries, (disclib->toc_count*sizeof(META_TITLE))); -+- disclib->toc_entries[i].title_number = atoi((const char*)tmp); -+- disclib->toc_entries[i].title_name = (char*)xmlNodeGetContent(cur_node); -++ META_TITLE *new_entries = realloc(disclib->toc_entries, ((disclib->toc_count + 1)*sizeof(META_TITLE))); -++ if (new_entries) { -++ int i = disclib->toc_count; -++ disclib->toc_count++; -++ disclib->toc_entries = new_entries; -++ disclib->toc_entries[i].title_number = atoi((const char*)tmp); -++ disclib->toc_entries[i].title_name = (char*)xmlNodeGetContent(cur_node); -++ } -+ XML_FREE(tmp); -+ } -+ } -+ else if (xmlStrEqual(cur_node->parent->name, BAD_CAST_CONST "description")) { -+ if (xmlStrEqual(cur_node->name, BAD_CAST_CONST "thumbnail") && (tmp = xmlGetProp(cur_node, BAD_CAST_CONST "href"))) { -+- uint8_t i = disclib->thumb_count; -+- disclib->thumb_count++; -+- disclib->thumbnails = realloc(disclib->thumbnails, (disclib->thumb_count*sizeof(META_THUMBNAIL))); -+- disclib->thumbnails[i].path = (char *)tmp; -+- if ((tmp = xmlGetProp(cur_node, BAD_CAST_CONST "size"))) { -+- int x = 0, y = 0; -+- sscanf((const char*)tmp, "%ix%i", &x, &y); -+- disclib->thumbnails[i].xres = x; -+- disclib->thumbnails[i].yres = y; -+- XML_FREE(tmp); -+- } -+- else { -+- disclib->thumbnails[i].xres = disclib->thumbnails[i].yres = -1; -++ META_THUMBNAIL *new_thumbnails = realloc(disclib->thumbnails, ((disclib->thumb_count + 1)*sizeof(META_THUMBNAIL))); -++ if (new_thumbnails) { -++ uint8_t i = disclib->thumb_count; -++ disclib->thumb_count++; -++ disclib->thumbnails = new_thumbnails; -++ disclib->thumbnails[i].path = (char *)tmp; -++ if ((tmp = xmlGetProp(cur_node, BAD_CAST_CONST "size"))) { -++ int x = 0, y = 0; -++ sscanf((const char*)tmp, "%ix%i", &x, &y); -++ disclib->thumbnails[i].xres = x; -++ disclib->thumbnails[i].yres = y; -++ XML_FREE(tmp); -++ } -++ else { -++ disclib->thumbnails[i].xres = disclib->thumbnails[i].yres = -1; -++ } -+ } -+ } -+ } -+@@ -126,15 +132,18 @@ static void _findMetaXMLfiles(META_ROOT *meta, BD_DISC *disc) -+ if (ent.d_name[0] == '.') -+ continue; -+ else if (strncasecmp(ent.d_name, "bdmt_", 5) == 0) { -+- uint8_t i = meta->dl_count; -+- meta->dl_count++; -+- meta->dl_entries = realloc(meta->dl_entries, (meta->dl_count*sizeof(META_DL))); -+- memset(&meta->dl_entries[i], 0, sizeof(meta->dl_entries[i])); -+- -+- meta->dl_entries[i].filename = str_dup(ent.d_name); -+- strncpy(meta->dl_entries[i].language_code, ent.d_name+5,3); -+- meta->dl_entries[i].language_code[3] = '\0'; -+- str_tolower(meta->dl_entries[i].language_code); -++ META_DL *new_dl_entries = realloc(meta->dl_entries, ((meta->dl_count + 1)*sizeof(META_DL))); -++ if (new_dl_entries) { -++ uint8_t i = meta->dl_count; -++ meta->dl_count++; -++ meta->dl_entries = new_dl_entries; -++ memset(&meta->dl_entries[i], 0, sizeof(meta->dl_entries[i])); -++ -++ meta->dl_entries[i].filename = str_dup(ent.d_name); -++ strncpy(meta->dl_entries[i].language_code, ent.d_name+5,3); -++ meta->dl_entries[i].language_code[3] = '\0'; -++ str_tolower(meta->dl_entries[i].language_code); -++ } -+ } -+ } -+ dir_close(dir); -+@@ -145,6 +154,10 @@ META_ROOT *meta_parse(BD_DISC *disc) -+ { -+ #ifdef HAVE_LIBXML2 -+ META_ROOT *root = calloc(1, sizeof(META_ROOT)); -++ if (!root) { -++ BD_DEBUG(DBG_CRIT, "out of memory\n"); -++ return NULL; -++ } -+ root->dl_count = 0; -+ -+ xmlDocPtr doc; +diff --git a/src/libbluray/bdnav/mpls_parse.c b/src/libbluray/bdnav/mpls_parse.c -+index da01f7b..8bfbb8c 100644 ++index e196118..87b240a 100644 +--- a/src/libbluray/bdnav/mpls_parse.c ++++ b/src/libbluray/bdnav/mpls_parse.c +@@ -39,6 +39,7 @@ @@ -77289,7 +51083,7 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + if (id2 == 2) { + // SubPath entries extension +diff --git a/src/libbluray/bdnav/mpls_parse.h b/src/libbluray/bdnav/mpls_parse.h -+index f9f7a18..94add53 100644 ++index 94bfa67..c1b2c31 100644 +--- a/src/libbluray/bdnav/mpls_parse.h ++++ b/src/libbluray/bdnav/mpls_parse.h +@@ -49,6 +49,7 @@ typedef struct @@ -77300,7 +51094,7 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + } MPLS_STREAM; + + typedef struct -+@@ -110,6 +111,7 @@ typedef struct ++@@ -109,6 +110,7 @@ typedef struct + uint8_t random_access_flag; + uint8_t audio_mix_flag; + uint8_t lossless_bypass_flag; @@ -77308,292 +51102,11 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + } MPLS_AI; + + typedef struct -+diff --git a/src/libbluray/bdnav/navigation.c b/src/libbluray/bdnav/navigation.c -+index db7fa9f..cfd7739 100644 -+--- a/src/libbluray/bdnav/navigation.c -++++ b/src/libbluray/bdnav/navigation.c -+@@ -174,6 +174,21 @@ _pl_duration(MPLS_PL *pl) -+ return duration; -+ } -+ -++static uint32_t -++_pl_chapter_count(MPLS_PL *pl) -++{ -++ unsigned ii, chapters = 0; -++ -++ // Count the number of "entry" marks (skipping "link" marks) -++ // This is the the number of chapters -++ for (ii = 0; ii < pl->mark_count; ii++) { -++ if (pl->play_mark[ii].mark_type == BD_MARK_ENTRY) { -++ chapters++; -++ } -++ } -++ return chapters; -++} -++ -+ NAV_TITLE_LIST* nav_get_title_list(BD_DISC *disc, uint32_t flags, uint32_t min_title_length) -+ { -+ BD_DIR_H *dir; -+@@ -403,15 +418,20 @@ static void _fill_clip(NAV_TITLE *title, -+ strncpy(&clip->name[5], ".m2ts", 6); -+ clip->clip_id = atoi(mpls_clip[clip->angle].clip_id); -+ -+- file = str_printf("%s.clpi", mpls_clip[clip->angle].clip_id); -+ clpi_free(clip->cl); -+- clip->cl = clpi_get(title->disc, file); -+- X_FREE(file); -++ clip->cl = NULL; -++ -++ file = str_printf("%s.clpi", mpls_clip[clip->angle].clip_id); -++ if (file) { -++ clip->cl = clpi_get(title->disc, file); -++ X_FREE(file); -++ } -+ if (clip->cl == NULL) { -+ clip->start_pkt = 0; -+ clip->end_pkt = 0; -+ return; -+ } -++ -+ switch (connection_condition) { -+ case 5: -+ case 6: -+@@ -441,7 +461,7 @@ static void _fill_clip(NAV_TITLE *title, -+ NAV_TITLE* nav_title_open(BD_DISC *disc, const char *playlist, unsigned angle) -+ { -+ NAV_TITLE *title = NULL; -+- unsigned ii, ss, chapters = 0; -++ unsigned ii, ss; -+ uint32_t pos = 0; -+ uint32_t time = 0; -+ -+@@ -501,15 +521,8 @@ NAV_TITLE* nav_title_open(BD_DISC *disc, const char *playlist, unsigned angle) -+ } -+ } -+ -+- // Count the number of "entry" marks (skipping "link" marks) -+- // This is the the number of chapters -+- for (ii = 0; ii < title->pl->mark_count; ii++) { -+- if (title->pl->play_mark[ii].mark_type == BD_MARK_ENTRY) { -+- chapters++; -+- } -+- } -+- title->chap_list.count = chapters; -+- title->chap_list.mark = calloc(chapters, sizeof(NAV_MARK)); -++ title->chap_list.count = _pl_chapter_count(title->pl); -++ title->chap_list.mark = calloc(title->chap_list.count, sizeof(NAV_MARK)); -+ title->mark_list.count = title->pl->mark_count; -+ title->mark_list.mark = calloc(title->pl->mark_count, sizeof(NAV_MARK)); -+ -+@@ -526,19 +539,29 @@ void nav_title_close(NAV_TITLE *title) -+ { -+ unsigned ii, ss; -+ -+- for (ss = 0; ss < title->sub_path_count; ss++) { -+- for (ii = 0; ii < title->sub_path[ss].clip_list.count; ii++) { -+- clpi_free(title->sub_path[ss].clip_list.clip[ii].cl); -++ if (!title) -++ return; -++ -++ if (title->sub_path) { -++ for (ss = 0; ss < title->sub_path_count; ss++) { -++ if (title->sub_path[ss].clip_list.clip) { -++ for (ii = 0; ii < title->sub_path[ss].clip_list.count; ii++) { -++ clpi_free(title->sub_path[ss].clip_list.clip[ii].cl); -++ } -++ X_FREE(title->sub_path[ss].clip_list.clip); -++ } -+ } -+- X_FREE(title->sub_path[ss].clip_list.clip); -++ X_FREE(title->sub_path); -+ } -+- X_FREE(title->sub_path); -+ -+- for (ii = 0; ii < title->pl->list_count; ii++) { -+- clpi_free(title->clip_list.clip[ii].cl); -++ if (title->clip_list.clip) { -++ for (ii = 0; ii < title->clip_list.count; ii++) { -++ clpi_free(title->clip_list.clip[ii].cl); -++ } -++ X_FREE(title->clip_list.clip); -+ } -++ -+ mpls_free(title->pl); -+- X_FREE(title->clip_list.clip); -+ X_FREE(title->chap_list.mark); -+ X_FREE(title->mark_list.mark); -+ X_FREE(title); -+diff --git a/src/libbluray/bdnav/sound_parse.c b/src/libbluray/bdnav/sound_parse.c -+index c1cbcfb..7c267da 100644 -+--- a/src/libbluray/bdnav/sound_parse.c -++++ b/src/libbluray/bdnav/sound_parse.c -+@@ -65,6 +65,7 @@ static int _sound_parse_attributes(BITSTREAM *bs, SOUND_OBJECT *obj) -+ -+ switch (i = bs_read(bs, 4)) { -+ default: BD_DEBUG(DBG_NAV, "unknown channel configuration code %d\n", i); -++ /* fall thru */ -+ case 1: obj->num_channels = 1; -+ break; -+ case 3: obj->num_channels = 2; -+@@ -72,11 +73,13 @@ static int _sound_parse_attributes(BITSTREAM *bs, SOUND_OBJECT *obj) -+ }; -+ switch (i = bs_read(bs, 4)) { -+ default: BD_DEBUG(DBG_NAV, "unknown sample rate code %d\n", i); -++ /* fall thru */ -+ case 1: obj->sample_rate = 48000; -+ break; -+ }; -+ switch (i = bs_read(bs, 2)) { -+ default: BD_DEBUG(DBG_NAV, "unknown bits per sample code %d\n", i); -++ /* fall thru */ -+ case 1: obj->bits_per_sample = 16; -+ break; -+ }; -+@@ -103,7 +106,15 @@ static int _sound_read_samples(BITSTREAM *bs, SOUND_OBJECT *obj) -+ uint32_t n; -+ uint32_t num_samples = obj->num_frames * obj->num_channels; -+ -++ if (!num_samples) { -++ return 1; -++ } -++ -+ obj->samples = calloc(num_samples, sizeof(uint16_t)); -++ if (!obj->samples) { -++ BD_DEBUG(DBG_CRIT, "out of memory\n"); -++ return 0; -++ } -+ -+ for (n = 0; n < num_samples; n++) { -+ obj->samples[n] = bs_read(bs, 16); -+@@ -116,13 +127,14 @@ void sound_free(SOUND_DATA **p) -+ { -+ if (p && *p) { -+ -+- unsigned i; -+- for (i = 0 ; i < (*p)->num_sounds; i++) { -+- X_FREE((*p)->sounds[i].samples); -+- } -+- -+- X_FREE((*p)->sounds); -++ if ((*p)->sounds) { -++ unsigned i; -++ for (i = 0 ; i < (*p)->num_sounds; i++) { -++ X_FREE((*p)->sounds[i].samples); -++ } -+ -++ X_FREE((*p)->sounds); -++ } -+ X_FREE(*p); -+ } -+ } -+@@ -150,21 +162,29 @@ static SOUND_DATA *_sound_parse(BD_FILE_H *fp) -+ bs_skip(&bs, 8); /* reserved */ -+ num_sounds = bs_read(&bs, 8); -+ -+- if (data_len < 1) { -++ if (data_len < 1 || num_sounds < 1) { -+ BD_DEBUG(DBG_NAV | DBG_CRIT, "empty database\n"); -+ goto error; -+ } -+ -+ data_offsets = calloc(num_sounds, sizeof(uint32_t)); -+ data = calloc(1, sizeof(SOUND_DATA)); -++ if (!data_offsets || !data) { -++ BD_DEBUG(DBG_CRIT, "out of memory\n"); -++ goto error; -++ } -+ data->num_sounds = num_sounds; -+ data->sounds = calloc(num_sounds, sizeof(SOUND_OBJECT)); -++ if (!data->sounds) { -++ BD_DEBUG(DBG_CRIT, "out of memory\n"); -++ goto error; -++ } -+ -+ /* parse headers */ -+ -+ for (i = 0; i < data->num_sounds; i++) { -+ if (!_sound_parse_index(&bs, data_offsets + i, &data->sounds[i])) { -+- BD_DEBUG(DBG_NAV | DBG_CRIT, "error parsing sound %d attribues\n", i); -++ BD_DEBUG(DBG_NAV | DBG_CRIT, "error parsing sound %d attributes\n", i); -+ goto error; -+ } -+ } +diff --git a/src/libbluray/bluray.c b/src/libbluray/bluray.c -+index eba9c5e..27beed7 100644 ++index 0e60b68..f633d7a 100644 +--- a/src/libbluray/bluray.c ++++ b/src/libbluray/bluray.c -+@@ -42,6 +42,7 @@ -+ #include "hdmv/hdmv_vm.h" -+ #include "hdmv/mobj_parse.h" -+ #include "decoders/graphics_controller.h" -++#include "decoders/hdmv_pids.h" -+ #include "decoders/m2ts_filter.h" -+ #include "decoders/overlay.h" -+ #include "disc/disc.h" -+@@ -93,6 +94,7 @@ typedef struct { -+ /* */ -+ uint8_t eof_hit; -+ uint8_t encrypted_block_cnt; -++ uint8_t seek_flag; /* used to fine-tune first read after seek */ -+ -+ M2TS_FILTER *m2ts_filter; -+ } BD_STREAM; -+@@ -202,7 +204,9 @@ static void _init_event_queue(BLURAY *bd) -+ { -+ if (!bd->event_queue) { -+ bd->event_queue = calloc(1, sizeof(struct bd_event_queue_s)); -+- bd_mutex_init(&bd->event_queue->mutex); -++ if (bd->event_queue) { -++ bd_mutex_init(&bd->event_queue->mutex); -++ } -+ } else { -+ bd_mutex_lock(&bd->event_queue->mutex); -+ bd->event_queue->in = 0; -+@@ -794,7 +798,15 @@ static int _preload_m2ts(BLURAY *bd, BD_PRELOAD *p) -+ -+ /* allocate buffer */ -+ p->clip_size = (size_t)st.clip_size; -+- p->buf = realloc(p->buf, p->clip_size); -++ uint8_t* tmp = (uint8_t*)realloc(p->buf, p->clip_size); -++ if (!tmp) { -++ BD_DEBUG(DBG_BLURAY | DBG_CRIT, "_preload_m2ts(): out of memory\n"); -++ _close_m2ts(&st); -++ _close_preload(p); -++ return 0; -++ } -++ -++ p->buf = tmp; -+ -+ /* read clip to buffer */ -+ -+@@ -847,6 +859,7 @@ static int64_t _seek_stream(BLURAY *bd, BD_STREAM *st, -+ } -+ -+ st->int_buf_off = 6144; -++ st->seek_flag = 1; -+ -+ return st->clip_pos; -+ } -+@@ -939,6 +952,7 @@ static void _fill_disc_info(BLURAY *bd, BD_ENC_INFO *enc_info) -+ bd->disc_info.bdplus_handled = enc_info->bdplus_handled; -+ bd->disc_info.bdplus_gen = enc_info->bdplus_gen; -+ bd->disc_info.bdplus_date = enc_info->bdplus_date; -++ bd->disc_info.no_menu_support = enc_info->no_menu_support; -+ -+ bd->disc_info.udf_volume_id = disc_volume_id(bd->disc); -+ -+@@ -1085,6 +1099,10 @@ static void _fill_disc_info(BLURAY *bd, BD_ENC_INFO *enc_info) -+ indx_free(&index); -+ } -+ -++ if (!bd->disc_info.first_play_supported || !bd->disc_info.top_menu_supported) { -++ bd->disc_info.no_menu_support = 1; -++ } -++ -+ if (bd->disc_info.bdj_detected) { -+ BDID_DATA *bdid = bdid_get(bd->disc); /* parse id.bdmv */ -+ if (bdid) { -+@@ -1624,6 +1642,25 @@ int64_t bd_seek_time(BLURAY *bd, uint64_t tick) ++@@ -1626,6 +1626,25 @@ int64_t bd_seek_time(BLURAY *bd, uint64_t tick) + return bd->s_pos; + } + @@ -77619,82 +51132,7 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + uint64_t bd_tell_time(BLURAY *bd) + { + uint32_t clip_pkt = 0, out_pkt = 0, out_time = 0; -+@@ -1956,6 +1993,19 @@ static int _bd_read(BLURAY *bd, unsigned char *buf, int len) -+ /* fatal error */ -+ return -1; -+ } -++ -++ /* finetune seek point (avoid skipping PAT/PMT/PCR) */ -++ if (BD_UNLIKELY(st->seek_flag)) { -++ st->seek_flag = 0; -++ -++ /* rewind if previous packets contain PAT/PMT/PCR */ -++ while (st->int_buf_off >= 192 && TS_PID(bd->int_buf + st->int_buf_off - 192) <= HDMV_PID_PCR) { -++ st->clip_pos -= 192; -++ st->int_buf_off -= 192; -++ bd->s_pos -= 192; -++ } -++ } -++ -+ } -+ if (size > (unsigned int)6144 - st->int_buf_off) { -+ size = 6144 - st->int_buf_off; -+@@ -2081,12 +2131,14 @@ static int _preload_textst_subpath(BLURAY *bd) -+ gc_add_font(bd->graphics_controller, NULL, -1); -+ for (ii = 0; ii < bd->st_textst.clip->cl->font_info.font_count; ii++) { -+ char *file = str_printf("%s.otf", bd->st_textst.clip->cl->font_info.font[ii].file_id); -+- uint8_t *data = NULL; -+- size_t size = disc_read_file(bd->disc, "BDMV" DIR_SEP "AUXDATA", file, &data); -+- if (data && size > 0 && gc_add_font(bd->graphics_controller, data, size) < 0) { -+- X_FREE(data); -++ if (file) { -++ uint8_t *data = NULL; -++ size_t size = disc_read_file(bd->disc, "BDMV" DIR_SEP "AUXDATA", file, &data); -++ if (data && size > 0 && gc_add_font(bd->graphics_controller, data, size) < 0) { -++ X_FREE(data); -++ } -++ X_FREE(file); -+ } -+- X_FREE(file); -+ } -+ gc_run(bd->graphics_controller, GC_CTRL_PG_CHARCODE, char_code, NULL); -+ -+@@ -2278,6 +2330,8 @@ static int _open_playlist(BLURAY *bd, const char *f_name, unsigned angle) -+ -+ _preload_subpaths(bd); -+ -++ bd->st0.seek_flag = 1; -++ -+ return 1; -+ } -+ return 0; -+@@ -2285,9 +2339,14 @@ static int _open_playlist(BLURAY *bd, const char *f_name, unsigned angle) -+ -+ int bd_select_playlist(BLURAY *bd, uint32_t playlist) -+ { -+- char *f_name = str_printf("%05d.mpls", playlist); -++ char *f_name; -+ int result; -+ -++ f_name = str_printf("%05d.mpls", playlist); -++ if (!f_name) { -++ return 0; -++ } -++ -+ bd_mutex_lock(&bd->mutex); -+ -+ if (bd->title_list) { -+@@ -2504,6 +2563,9 @@ uint32_t bd_get_titles(BLURAY *bd, uint8_t flags, uint32_t min_title_length) -+ -+ int bd_get_main_title(BLURAY *bd) -+ { -++ if (!bd) { -++ return -1; -++ } -+ if (bd->title_type != title_undef) { -+ BD_DEBUG(DBG_CRIT | DBG_BLURAY, "bd_get_main_title() can't be used with BluRay menus\n"); -+ } -+@@ -2571,6 +2633,7 @@ static BLURAY_TITLE_INFO* _fill_title_info(NAV_TITLE* title, uint32_t title_idx, ++@@ -2602,6 +2621,7 @@ static BLURAY_TITLE_INFO* _fill_title_info(NAV_TITLE* title, uint32_t title_idx, + BLURAY_CLIP_INFO *ci = &title_info->clips[ii]; + NAV_CLIP *nc = &title->clip_list.clip[ii]; + @@ -77702,7 +51140,7 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + ci->pkt_count = nc->end_pkt - nc->start_pkt; + ci->start_time = (uint64_t)nc->title_time * 2; + ci->in_time = (uint64_t)pi->in_time * 2; -+@@ -2597,6 +2660,8 @@ static BLURAY_TITLE_INFO* _fill_title_info(NAV_TITLE* title, uint32_t title_idx, ++@@ -2628,6 +2648,8 @@ static BLURAY_TITLE_INFO* _fill_title_info(NAV_TITLE* title, uint32_t title_idx, + _copy_streams(nc, ci->sec_audio_streams, pi->stn.secondary_audio, ci->sec_audio_stream_count); + } + @@ -77711,135 +51149,7 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + return title_info; + } + -+@@ -2637,9 +2702,14 @@ BLURAY_TITLE_INFO* bd_get_title_info(BLURAY *bd, uint32_t title_idx, unsigned an -+ -+ BLURAY_TITLE_INFO* bd_get_playlist_info(BLURAY *bd, uint32_t playlist, unsigned angle) -+ { -+- char *f_name = str_printf("%05d.mpls", playlist); -++ char *f_name; -+ BLURAY_TITLE_INFO *title_info; -+ -++ f_name = str_printf("%05d.mpls", playlist); -++ if (!f_name) { -++ return NULL; -++ } -++ -+ title_info = _get_title_info(bd, 0, playlist, f_name, angle); -+ -+ X_FREE(f_name); -+@@ -2694,9 +2764,9 @@ int bd_set_player_setting(BLURAY *bd, uint32_t idx, uint32_t value) -+ bd_mutex_lock(&bd->mutex); -+ -+ bd->decode_pg = !!value; -+- result = bd_psr_write_bits(bd->regs, PSR_PG_STREAM, -+- (!!value) << 31, -+- 0x80000000); -++ result = !bd_psr_write_bits(bd->regs, PSR_PG_STREAM, -++ (!!value) << 31, -++ 0x80000000); -+ -+ bd_mutex_unlock(&bd->mutex); -+ return result; -+@@ -2705,7 +2775,7 @@ int bd_set_player_setting(BLURAY *bd, uint32_t idx, uint32_t value) -+ for (i = 0; i < sizeof(map) / sizeof(map[0]); i++) { -+ if (idx == map[i].idx) { -+ bd_mutex_lock(&bd->mutex); -+- result = !bd_psr_setting_write(bd->regs, idx, value); -++ result = !bd_psr_setting_write(bd->regs, map[i].psr, value); -+ bd_mutex_unlock(&bd->mutex); -+ return result; -+ } -+@@ -2756,6 +2826,9 @@ void bd_select_stream(BLURAY *bd, uint32_t stream_type, uint32_t stream_id, uint -+ bd_mutex_lock(&bd->mutex); -+ -+ switch (stream_type) { -++ case BLURAY_AUDIO_STREAM: -++ bd_psr_write(bd->regs, PSR_PRIMARY_AUDIO_ID, stream_id & 0xff); -++ break; -+ case BLURAY_PG_TEXTST_STREAM: -+ bd_psr_write_bits(bd->regs, PSR_PG_STREAM, -+ ((!!enable_flag)<<31) | (stream_id & 0xfff), -+@@ -3076,6 +3149,11 @@ static int _play_title(BLURAY *bd, unsigned title) -+ return 0; -+ } -+ -++ if (bd->disc_info.no_menu_support) { -++ BD_DEBUG(DBG_BLURAY | DBG_CRIT, "bd_play(): no menu support\n"); -++ return 0; -++ } -++ -+ /* first play object ? */ -+ if (title == BLURAY_TITLE_FIRST_PLAY) { -+ -+@@ -3203,6 +3281,12 @@ static int _try_play_title(BLURAY *bd, unsigned title) -+ int bd_play_title(BLURAY *bd, unsigned title) -+ { -+ int ret; -++ -++ if (title == BLURAY_TITLE_TOP_MENU) { -++ /* menu call uses different UO mask */ -++ return bd_menu_call(bd, -1); -++ } -++ -+ bd_mutex_lock(&bd->mutex); -+ ret = _try_play_title(bd, title); -+ bd_mutex_unlock(&bd->mutex); -+@@ -3561,7 +3645,37 @@ int bd_get_sound_effect(BLURAY *bd, unsigned sound_id, BLURAY_SOUND_EFFECT *effe -+ } -+ -+ /* -+- * -++ * Direct file access -++ */ -++ -++static int _bd_read_file(BLURAY *bd, const char *dir, const char *file, void **data, int64_t *size) -++{ -++ if (!bd || !bd->disc || !file || !data || !size) { -++ BD_DEBUG(DBG_CRIT, "Invalid arguments for bd_read_file()\n"); -++ return 0; -++ } -++ -++ *data = NULL; -++ *size = (int64_t)disc_read_file(bd->disc, dir, file, (uint8_t**)data); -++ if (!*data || *size < 0) { -++ BD_DEBUG(DBG_BLURAY, "bd_read_file() failed\n"); -++ X_FREE(*data); -++ return 0; -++ } -++ -++ BD_DEBUG(DBG_BLURAY, "bd_read_file(): read %"PRId64" bytes from %s"DIR_SEP"%s\n", -++ *size, dir, file); -++ return 1; -++} -++ -++int bd_read_file(BLURAY *bd, const char *path, void **data, int64_t *size) -++{ -++ return _bd_read_file(bd, NULL, path, data, size); -++} -++ -++ -++/* -++ * Metadata -+ */ -+ -+ const struct meta_dl *bd_get_meta(BLURAY *bd) -+@@ -3598,6 +3712,15 @@ const struct meta_dl *bd_get_meta(BLURAY *bd) -+ return meta; -+ } -+ -++int bd_get_meta_file(BLURAY *bd, const char *name, void **data, int64_t *size) -++{ -++ return _bd_read_file(bd, DIR_SEP "BDMV" DIR_SEP "META" DIR_SEP "DL", name, data, size); -++} -++ -++/* -++ * Database access -++ */ -++ -+ struct clpi_cl *bd_get_clpi(BLURAY *bd, unsigned clip_ref) -+ { -+ if (bd->title && clip_ref < bd->title->clip_list.count) { -+@@ -3655,3 +3778,28 @@ void bd_free_bdjo(struct bdjo_data *obj) ++@@ -3746,3 +3768,28 @@ void bd_free_bdjo(struct bdjo_data *obj) + (void)obj; + #endif + } @@ -77869,7 +51179,7 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 ++ return NULL; ++} +diff --git a/src/libbluray/bluray.h b/src/libbluray/bluray.h -+index 6ade74b..6e74df4 100644 ++index cbf16fc..97dc1a3 100644 +--- a/src/libbluray/bluray.h ++++ b/src/libbluray/bluray.h +@@ -32,6 +32,7 @@ extern "C" { @@ -77880,17 +51190,7 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + + #define TITLES_ALL 0 /**< all titles. */ + #define TITLES_FILTER_DUP_TITLE 0x01 /**< remove duplicate titles. */ -+@@ -119,6 +120,9 @@ typedef struct { -+ char bdj_disc_id[33]; /* (BD-J) disc ID */ -+ -+ const char *udf_volume_id; /* optional UDF volume identifier */ -++ -++ uint8_t no_menu_support; /* 1 if this disc can't be played using on-disc menus */ -++ -+ } BLURAY_DISC_INFO; -+ -+ /* -+@@ -216,6 +220,7 @@ typedef struct bd_stream_info { ++@@ -225,6 +226,7 @@ typedef struct bd_stream_info { + } BLURAY_STREAM_INFO; + + typedef struct bd_clip { @@ -77898,7 +51198,7 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + uint32_t pkt_count; + uint8_t still_mode; + uint16_t still_time; /* seconds */ -+@@ -266,6 +271,8 @@ typedef struct bd_title_info { ++@@ -275,6 +277,8 @@ typedef struct bd_title_info { + + uint32_t mark_count; + BLURAY_TITLE_MARK *marks; @@ -77907,37 +51207,7 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + } BLURAY_TITLE_INFO; + + /* -+@@ -355,12 +362,29 @@ const BLURAY_DISC_INFO *bd_get_disc_info(BLURAY *bd); -+ * If information is provided in multiple languages, currently -+ * selected language (BLURAY_PLAYER_SETTING_MENU_LANG) is used. -+ * -++ * Referenced thumbnail images should be read with bd_get_meta_file(). -++ * -+ * @param bd BLURAY object -+ * @return META_DL (disclib) object, NULL on error -+ */ -+ struct meta_dl; -+ const struct meta_dl *bd_get_meta(BLURAY *bd); -+ -++/** -++ * -++ * Read metadata file from BluRay disc. -++ * -++ * Allocate large enough memory block and read file contents. -++ * Caller must free the memory block with free(). -++ * -++ * @param bd BLURAY object -++ * @param file_name name of metadata file -++ * @param data where to store pointer to file data -++ * @param size where to store file size -++ * @return 1 on success, 0 on error -++ */ -++int bd_get_meta_file(BLURAY *bd, const char *file_name, void **data, int64_t *size); -++ -+ -+ /* -+ * Title selection without on-disc menus -+@@ -441,6 +465,16 @@ uint32_t bd_get_current_title(BLURAY *bd); ++@@ -483,6 +487,16 @@ uint32_t bd_get_current_title(BLURAY *bd); + + /** + * @@ -77954,15 +51224,7 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + * Read from currently selected title file, decrypt if possible + * + * @param bd BLURAY object -+@@ -536,6 +570,7 @@ void bd_seamless_angle_change(BLURAY *bd, unsigned angle); -+ * @param stream_id stream number (1..N) -+ * @param enable_flag set to 0 to disable streams of this type -+ */ -++#define BLURAY_AUDIO_STREAM 0 -+ #define BLURAY_PG_TEXTST_STREAM 1 -+ -+ void bd_select_stream(BLURAY *bd, uint32_t stream_type, uint32_t stream_id, uint32_t enable_flag); -+@@ -963,7 +998,6 @@ int bd_mouse_select(BLURAY *bd, int64_t pts, uint16_t x, uint16_t y); ++@@ -1007,7 +1021,6 @@ int bd_mouse_select(BLURAY *bd, int64_t pts, uint16_t x, uint16_t y); + + /* access to internal information */ + @@ -77970,27 +51232,12 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + /** + * + * Get copy of clip information for requested playitem. -+@@ -1001,6 +1035,43 @@ void bd_free_bdjo(struct bdjo_data *); -+ int bd_start_bdj(BLURAY *bd, const char* start_object); // start BD-J from the specified BD-J object (should be a 5 character string) -+ void bd_stop_bdj(BLURAY *bd); // shutdown BD-J and clean up resources ++@@ -1060,6 +1073,28 @@ void bd_stop_bdj(BLURAY *bd); // shutdown BD-J and clean up resources ++ */ ++ int bd_read_file(BLURAY *, const char *path, void **data, int64_t *size); + ++/** ++ * -++ * Read a file from BluRay Virtual File System. -++ * -++ * Allocate large enough memory block and read file contents. -++ * Caller must free the memory block with free(). -++ * -++ * @param bd BLURAY object -++ * @param file_name path to the file (relative to disc root) -++ * @param data where to store pointer to allocated data -++ * @param size where to store file size -++ * @return 1 on success, 0 on error -++ */ -++int bd_read_file(BLURAY *, const char *path, void **data, int64_t *size); -++ -++/** -++ * ++ * Get information about the clip ++ * ++ * @param bd BLURAY object @@ -78014,527 +51261,24 @@ index 0000000000000000000000000000000000000000..5884d91590f80927cc5138fdd0ed4107 + + #ifdef __cplusplus + } -+diff --git a/src/libbluray/decoders/graphics_controller.c b/src/libbluray/decoders/graphics_controller.c -+index dabde1c..d3c775a 100644 -+--- a/src/libbluray/decoders/graphics_controller.c -++++ b/src/libbluray/decoders/graphics_controller.c -+@@ -825,6 +825,8 @@ void gc_free(GRAPHICS_CONTROLLER **p) -+ -+ bd_mutex_destroy(&gc->mutex); -+ -++ X_FREE(gc->saved_bog_data); -++ -+ X_FREE(*p); -+ } -+ } -+diff --git a/src/libbluray/decoders/hdmv_pids.h b/src/libbluray/decoders/hdmv_pids.h -+index ac5bc6a..45a55f3 100644 -+--- a/src/libbluray/decoders/hdmv_pids.h -++++ b/src/libbluray/decoders/hdmv_pids.h -+@@ -61,5 +61,12 @@ -+ #define IS_HDMV_PID_IG(pid) ((pid) >= HDMV_PID_IG_FIRST && (pid) <= HDMV_PID_IG_LAST) -+ #define IS_HDMV_PID_TEXTST(pid) ((pid) == HDMV_PID_TEXTST) -+ -++/* -++ * Extract PID from HDMV MPEG-TS packet -++ */ -++ -++#define TS_PID(buf) \ -++ ((((buf)[4+1] & 0x1f) << 8) | (buf)[4+2]) -++ -+ -+ #endif // _HDMV_PIDS_H_ -+diff --git a/src/libbluray/decoders/overlay.h b/src/libbluray/decoders/overlay.h -+index 6a31218..7daa478 100644 -+--- a/src/libbluray/decoders/overlay.h -++++ b/src/libbluray/decoders/overlay.h -+@@ -20,6 +20,10 @@ -+ #ifndef BD_OVERLAY_H_ -+ #define BD_OVERLAY_H_ -+ -++#ifdef __cplusplus -++extern "C" { -++#endif -++ -+ #include <stdint.h> -+ -+ #define BD_OVERLAY_INTERFACE_VERSION 2 -+@@ -199,4 +203,8 @@ typedef struct bd_argb_buffer_s { -+ -+ } BD_ARGB_BUFFER; -+ -++#ifdef __cplusplus -++} -++#endif -++ -+ #endif // BD_OVERLAY_H_ -+diff --git a/src/libbluray/decoders/textst_render.c b/src/libbluray/decoders/textst_render.c -+index 8d1527e..0e87d4b 100644 -+--- a/src/libbluray/decoders/textst_render.c -++++ b/src/libbluray/decoders/textst_render.c -+@@ -74,6 +74,10 @@ TEXTST_RENDER *textst_render_init(void) -+ #ifdef HAVE_FT2 -+ TEXTST_RENDER *p = calloc(1, sizeof(TEXTST_RENDER)); -+ -++ if (!p) { -++ return NULL; -++ } -++ -+ if (!FT_Init_FreeType(&p->ft_lib)) { -+ return p; -+ } -+diff --git a/src/libbluray/disc/aacs.c b/src/libbluray/disc/aacs.c -+index 217ef6f..9ae8efb 100644 -+--- a/src/libbluray/disc/aacs.c -++++ b/src/libbluray/disc/aacs.c -+@@ -47,6 +47,8 @@ struct bd_aacs { -+ fptr_p_void get_device_binding_id; -+ fptr_p_void get_device_nonce; -+ fptr_p_void get_media_key; -++ -++ int impl_id; -+ }; -+ -+ -+@@ -58,15 +60,19 @@ static void _libaacs_close(BD_AACS *p) -+ } -+ } -+ -+-void libaacs_unload(BD_AACS **p) -++static void _unload(BD_AACS *p) -+ { -+- if (p && *p) { -+- _libaacs_close(*p); -++ _libaacs_close(p); -+ -+- if ((*p)->h_libaacs) { -+- dl_dlclose((*p)->h_libaacs); -+- } -++ if (p->h_libaacs) { -++ dl_dlclose(p->h_libaacs); -++ } -++} -+ -++void libaacs_unload(BD_AACS **p) -++{ -++ if (p && *p) { -++ _unload(*p); -+ X_FREE(*p); -+ } -+ } -+@@ -82,7 +88,7 @@ int libaacs_required(void *have_file_handle, int (*have_file)(void *, const char -+ return 0; -+ } -+ -+-static void *_open_libaacs(void) -++static void *_open_libaacs(int *impl_id) -+ { -+ const char * const libaacs[] = { -+ getenv("LIBAACS_PATH"), -+@@ -91,10 +97,11 @@ static void *_open_libaacs(void) -+ }; -+ unsigned ii; -+ -+- for (ii = 0; ii < sizeof(libaacs) / sizeof(libaacs[0]); ii++) { -++ for (ii = *impl_id; ii < sizeof(libaacs) / sizeof(libaacs[0]); ii++) { -+ if (libaacs[ii]) { -+ void *handle = dl_dlopen(libaacs[ii], "0"); -+ if (handle) { -++ *impl_id = ii; -+ BD_DEBUG(DBG_BLURAY, "Using %s for AACS\n", libaacs[ii]); -+ return handle; -+ } -+@@ -105,11 +112,15 @@ static void *_open_libaacs(void) -+ return NULL; -+ } -+ -+-BD_AACS *libaacs_load(void) -++static BD_AACS *_load(int impl_id) -+ { -+ BD_AACS *p = calloc(1, sizeof(BD_AACS)); -++ if (!p) { -++ return NULL; -++ } -++ p->impl_id = impl_id; -+ -+- p->h_libaacs = _open_libaacs(); -++ p->h_libaacs = _open_libaacs(&p->impl_id); -+ if (!p->h_libaacs) { -+ X_FREE(p); -+ return NULL; -+@@ -140,6 +151,11 @@ BD_AACS *libaacs_load(void) -+ return p; -+ } -+ -++BD_AACS *libaacs_load(void) -++{ -++ return _load(0); -++} -++ -+ int libaacs_open(BD_AACS *p, const char *device, -+ void *file_open_handle, void *file_open_fp, -+ const char *keyfile_path) -+@@ -177,6 +193,22 @@ int libaacs_open(BD_AACS *p, const char *device, -+ BD_DEBUG(DBG_BLURAY, "aacs_open() not found\n"); -+ } -+ -++ if (error_code) { -++ /* failed. try next aacs implementation if available. */ -++ BD_AACS *p2 = _load(p->impl_id + 1); -++ if (p2) { -++ if (!libaacs_open(p2, device, file_open_handle, file_open_fp, keyfile_path)) { -++ /* succeed - swap implementations */ -++ _unload(p); -++ *p = *p2; -++ X_FREE(p2); -++ return 0; -++ } -++ /* failed - report original errors */ -++ libaacs_unload(&p2); -++ } -++ } -++ -+ if (p->aacs) { -+ if (aacs_get_mkb_version) { -+ p->mkbv = aacs_get_mkb_version(p->aacs); -+diff --git a/src/libbluray/disc/bdplus.c b/src/libbluray/disc/bdplus.c -+index b8c4d57..363719f 100644 -+--- a/src/libbluray/disc/bdplus.c -++++ b/src/libbluray/disc/bdplus.c -+@@ -107,6 +107,9 @@ static void *_libbdplus_open(void) -+ BD_BDPLUS *libbdplus_load(void) -+ { -+ BD_BDPLUS *p = calloc(1, sizeof(BD_BDPLUS)); -++ if (!p) { -++ return NULL; -++ } -+ -+ BD_DEBUG(DBG_BDPLUS, "attempting to load libbdplus\n"); -+ -+@@ -241,10 +244,12 @@ BD_BDPLUS_ST *libbdplus_m2ts(BD_BDPLUS *p, uint32_t clip_id, uint64_t pos) -+ if (!p->m2ts) { -+ /* use old API */ -+ BD_BDPLUS_ST *ret = calloc(1, sizeof(BD_BDPLUS_ST)); -+- ret->lib = p; -+- ret->st = NULL; -+- p->title(p->bdplus, clip_id); -+- p->seek(p->bdplus, pos); -++ if (ret) { -++ ret->lib = p; -++ ret->st = NULL; -++ p->title(p->bdplus, clip_id); -++ p->seek(p->bdplus, pos); -++ } -+ return ret; -+ } -+ -+@@ -258,9 +263,11 @@ BD_BDPLUS_ST *libbdplus_m2ts(BD_BDPLUS *p, uint32_t clip_id, uint64_t pos) -+ p->m2ts_close(st); -+ } else { -+ BD_BDPLUS_ST *ret = calloc(1, sizeof(BD_BDPLUS_ST)); -+- ret->lib = p; -+- ret->st = st; -+- BD_DEBUG(DBG_BLURAY | DBG_CRIT, "BD+ active for clip %05d.m2ts\n", clip_id); -++ if (ret) { -++ ret->lib = p; -++ ret->st = st; -++ BD_DEBUG(DBG_BLURAY | DBG_CRIT, "BD+ active for clip %05d.m2ts\n", clip_id); -++ } -+ return ret; -+ } -+ } -+diff --git a/src/libbluray/disc/dec.c b/src/libbluray/disc/dec.c -+index 694646e..1c8a601 100644 -+--- a/src/libbluray/disc/dec.c -++++ b/src/libbluray/disc/dec.c -+@@ -158,6 +158,10 @@ static int _bdrom_have_file(void *p, const char *dir, const char *file) -+ char *path; -+ -+ path = str_printf("%s" DIR_SEP "%s", dir, file); -++ if (!path) { -++ return 0; -++ } -++ -+ fp = dev->pf_file_open_bdrom(dev->file_open_bdrom_handle, path); -+ X_FREE(path); -+ -+@@ -175,6 +179,8 @@ static int _libaacs_init(BD_DEC *dec, struct dec_dev *dev, -+ int result; -+ const uint8_t *disc_id; -+ -++ memset(i, 0, sizeof(*i)); -++ -+ libaacs_unload(&dec->aacs); -+ -+ i->aacs_detected = libaacs_required((void*)dev, _bdrom_have_file); -+@@ -201,7 +207,7 @@ static int _libaacs_init(BD_DEC *dec, struct dec_dev *dev, -+ } -+ -+ if (result) { -+- BD_DEBUG(DBG_BLURAY | DBG_CRIT, "aacs_open() failed!\n"); -++ BD_DEBUG(DBG_BLURAY | DBG_CRIT, "aacs_open() failed: %d!\n", result); -+ libaacs_unload(&dec->aacs); -+ return 0; -+ } -+@@ -255,6 +261,13 @@ static int _libbdplus_init(BD_DEC *dec, struct dec_dev *dev, -+ i->bdplus_gen = libbdplus_get_gen(dec->bdplus); -+ i->bdplus_date = libbdplus_get_date(dec->bdplus); -+ i->bdplus_handled = 1; -++ -++ if (i->bdplus_date == 0) { -++ // libmmbd -> no menu support -++ BD_DEBUG(DBG_BLURAY | DBG_CRIT, "WARNING: using libmmbd for BD+. On-disc menus will not work.\n"); -++ i->no_menu_support = 1; -++ } -++ -+ return 1; -+ } -+ +diff --git a/src/libbluray/disc/disc.c b/src/libbluray/disc/disc.c -+index ecd53e3..757b6ed 100644 ++index defa084..375e6c3 100644 +--- a/src/libbluray/disc/disc.c ++++ b/src/libbluray/disc/disc.c -+@@ -65,7 +65,11 @@ static BD_FILE_H *_bdrom_open_path(void *p, const char *rel_path) -+ char *abs_path; ++@@ -69,7 +69,7 @@ static BD_FILE_H *_bdrom_open_path(void *p, const char *rel_path) ++ return NULL; ++ } + -+ abs_path = str_printf("%s%s", disc->disc_root, rel_path); +- fp = file_open(abs_path, "rb"); -++ if (!abs_path) { -++ return NULL; -++ } -++ ++ fp = file_open(abs_path, "rbS"); + X_FREE(abs_path); + + return fp; -+@@ -78,6 +82,10 @@ static BD_DIR_H *_bdrom_open_dir(void *p, const char *dir) -+ char *path; -+ -+ path = str_printf("%s%s", disc->disc_root, dir); -++ if (!path) { -++ return NULL; -++ } -++ -+ dp = dir_open(path); -+ X_FREE(path); -+ -+@@ -96,8 +104,10 @@ static BD_FILE_H *_overlay_open_path(BD_DISC *p, const char *rel_path) -+ -+ if (p->overlay_root) { -+ char *abs_path = str_printf("%s%s", p->overlay_root, rel_path); -+- fp = file_open(abs_path, "rb"); -+- X_FREE(abs_path); -++ if (abs_path) { -++ fp = file_open(abs_path, "rb"); -++ X_FREE(abs_path); -++ } -+ } -+ -+ bd_mutex_unlock(&p->ovl_mutex); -+@@ -113,8 +123,10 @@ static BD_DIR_H *_overlay_open_dir(BD_DISC *p, const char *dir) -+ -+ if (p->overlay_root) { -+ char *abs_path = str_printf("%s%s", p->disc_root, dir); -+- dp = dir_open_default()(abs_path); -+- X_FREE(abs_path); -++ if (abs_path) { -++ dp = dir_open_default()(abs_path); -++ X_FREE(abs_path); -++ } -+ } -+ -+ bd_mutex_unlock(&p->ovl_mutex); -+@@ -165,7 +177,7 @@ static void _comb_dir_append(BD_DIR_H *dp, BD_DIRENT *entry) -+ } -+ -+ /* append */ -+- priv = realloc(priv, sizeof(*priv) + priv->count * sizeof(BD_DIRENT)); -++ priv = realloc(dp->internal, sizeof(*priv) + priv->count * sizeof(BD_DIRENT)); -+ if (!priv) { -+ return; -+ } -+@@ -183,6 +195,10 @@ static BD_DIR_H *_combine_dirs(BD_DIR_H *ovl, BD_DIR_H *rom) -+ dp->read = _comb_dir_read; -+ dp->close = _comb_dir_close; -+ dp->internal = calloc(1, sizeof(COMB_DIR)); -++ if (!dp->internal) { -++ X_FREE(dp); -++ goto out; -++ } -+ -+ while (!dir_read(ovl, &entry)) { -+ _comb_dir_append(dp, &entry); -+@@ -191,6 +207,8 @@ static BD_DIR_H *_combine_dirs(BD_DIR_H *ovl, BD_DIR_H *rom) -+ _comb_dir_append(dp, &entry); -+ } -+ } -++ -++ out: -+ dir_close(ovl); -+ dir_close(rom); -+ -+@@ -342,6 +360,10 @@ BD_FILE_H *disc_open_file(BD_DISC *p, const char *dir, const char *file) -+ char *path; -+ -+ path = str_printf("%s" DIR_SEP "%s", dir, file); -++ if (!path) { -++ return NULL; -++ } -++ -+ fp = disc_open_path(p, path); -+ X_FREE(path); -+ -+@@ -377,7 +399,11 @@ size_t disc_read_file(BD_DISC *disc, const char *dir, const char *file, -+ -+ *data = NULL; -+ -+- fp = disc_open_file(disc, dir, file); -++ if (dir) { -++ fp = disc_open_file(disc, dir, file); -++ } else { -++ fp = disc_open_path(disc, file); -++ } -+ if (!fp) { -+ return 0; -+ } -+@@ -454,7 +480,7 @@ int disc_cache_bdrom_file(BD_DISC *p, const char *rel_path, const char *cache_pa -+ BD_DEBUG(DBG_FILE | DBG_CRIT, "error caching file %s\n", rel_path); -+ file_close(fp_out); -+ file_close(fp_in); -+- file_unlink(cache_path); -++ (void)file_unlink(cache_path); -+ return -1; -+ } -+ } -+diff --git a/src/libbluray/disc/enc_info.h b/src/libbluray/disc/enc_info.h -+index d45d891..47ca94f 100644 -+--- a/src/libbluray/disc/enc_info.h -++++ b/src/libbluray/disc/enc_info.h -+@@ -34,6 +34,8 @@ typedef struct bd_enc_info { -+ uint8_t disc_id[20]; -+ uint8_t bdplus_gen; -+ uint32_t bdplus_date; -++ -++ uint8_t no_menu_support; -+ } BD_ENC_INFO; -+ -+ #endif /* _BD_DISC_ENC_INFO_H_ */ -+diff --git a/src/libbluray/disc/udf_fs.c b/src/libbluray/disc/udf_fs.c -+index 1eec761..3e438ca 100644 -+--- a/src/libbluray/disc/udf_fs.c -++++ b/src/libbluray/disc/udf_fs.c -+@@ -67,6 +67,9 @@ static int64_t _file_read(BD_FILE_H *file, uint8_t *buf, int64_t size) -+ BD_FILE_H *udf_file_open(void *udf, const char *filename) -+ { -+ BD_FILE_H *file = calloc(1, sizeof(BD_FILE_H)); -++ if (!file) { -++ return NULL; -++ } -+ -+ BD_DEBUG(DBG_FILE, "Opening UDF file %s... (%p)\n", filename, (void*)file); -+ -+@@ -116,6 +119,9 @@ static int _dir_read(BD_DIR_H *dir, BD_DIRENT *entry) -+ BD_DIR_H *udf_dir_open(void *udf, const char* dirname) -+ { -+ BD_DIR_H *dir = calloc(1, sizeof(BD_DIR_H)); -++ if (!dir) { -++ return NULL; -++ } -+ -+ BD_DEBUG(DBG_DIR, "Opening UDF dir %s... (%p)\n", dirname, (void*)dir); -+ -+diff --git a/src/libbluray/hdmv/mobj_print.c b/src/libbluray/hdmv/mobj_print.c -+index 5c5313e..4361a76 100644 -+--- a/src/libbluray/hdmv/mobj_print.c -++++ b/src/libbluray/hdmv/mobj_print.c -+@@ -159,6 +159,7 @@ static const char * const psr_info[128] = { -+ /* PSR127 */ NULL, -+ }; -+ -++#if 0 -+ static const char * const insn_groups[4] = { -+ "BRANCH", -+ "COMPARE", -+@@ -175,6 +176,7 @@ static const char * const insn_group_set[8] = { -+ "SET", -+ "SETSYSTEM", -+ }; -++#endif -+ -+ static const char * const insn_opt_set[32] = { -+ NULL, -+diff --git a/src/util/logging.c b/src/util/logging.c -+index b8ef1f5..62e6b59 100644 -+--- a/src/util/logging.c -++++ b/src/util/logging.c -+@@ -81,19 +81,34 @@ void bd_debug(const char *file, int line, uint32_t mask, const char *format, ... -+ -+ if (mask & debug_mask) { -+ const char *f = strrchr(file, DIR_SEP_CHAR); -+- char buffer[4096], *pt = buffer; -++ char buffer[4096]; -+ va_list args; -++ int len, len2; -+ -+- pt += sprintf(buffer, "%s:%d: ", f ? f + 1 : file, line); -++ len = sprintf(buffer, "%s:%d: ", f ? f + 1 : file, line); -++ if (len < 0) { -++ return; -++ } -+ -+ va_start(args, format); -+- vsnprintf(pt, sizeof(buffer) - (size_t)(intptr_t)(pt - buffer) - 1, format, args); -++ len2 = vsnprintf(buffer + len, sizeof(buffer) - len - 1, format, args); -+ va_end(args); -+ -++ if (len2 < 0) { -++ return; -++ } -++ -+ if (log_func) { -++ buffer[sizeof(buffer)-1] = 0; -+ log_func(buffer); -++ -+ } else { -+- fprintf(logfile, "%s", buffer); -++ len += len2; -++ if ((size_t)len >= sizeof(buffer)) { -++ len = sizeof(buffer); -++ } -++ -++ fwrite(buffer, len, 1, logfile); -+ } -+ } -+ } -+diff --git a/src/util/refcnt.h b/src/util/refcnt.h -+index b839eba..9164921 100644 -+--- a/src/util/refcnt.h -++++ b/src/util/refcnt.h -+@@ -20,6 +20,10 @@ -+ #ifndef BD_REFCNT_H_ -+ #define BD_REFCNT_H_ -+ -++#ifdef __cplusplus -++extern "C" { -++#endif -++ -+ #include "attributes.h" -+ -+ #include <stddef.h> -+@@ -53,4 +57,8 @@ void bd_refcnt_inc(const void *obj); -+ void bd_refcnt_dec(const void *obj); -+ #endif -+ -++#ifdef __cplusplus -++} -++#endif -++ -+ #endif // BD_REFCNT_H_ -From 5e19f7192303245587548c2564d1e1711019a565 Mon Sep 17 00:00:00 2001 +From b1af1a3caed688d7690a40b24f3db8480c415382 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Wed, 2 Mar 2016 19:40:47 +0000 -Subject: [PATCH 48/67] [VideoPlayer] Added new msdk-mvc decoder. +Subject: [PATCH 46/61] [VideoPlayer] Added new msdk-mvc decoder. --- xbmc/cores/VideoPlayer/DVDCodecs/DVDCodecUtils.cpp | 61 ++++++++++++++++++++++ @@ -78650,10 +51394,10 @@ index eb76a6fe73f6c884540807cfb93c7a3ecc4eea90..7e24c2364e8d2efa9b8351afc041aa14 static int PixfmtFromEFormat(ERenderFormat format); }; -From 38596e0f01d1235fe66c4891818f203e676bf6af Mon Sep 17 00:00:00 2001 +From 411ae88ce803806ae1581960ba2c2f4a7474164a Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Sun, 6 Mar 2016 12:54:59 +0000 -Subject: [PATCH 49/67] mvc: Automatically enable stereo mode +Subject: [PATCH 47/61] mvc: Automatically enable stereo mode --- xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp | 6 +++++- @@ -78661,10 +51405,10 @@ Subject: [PATCH 49/67] mvc: Automatically enable stereo mode 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -index 8691b086a46fcdd03eee809a53ea9b20f74dcc05..b4e2c57d406297f75c5dfc0217f4d33507cb6755 100644 +index 283b2626731c25c67e4c065dac7725a488c09523..a253b7fe8c591ba318958ea133355febb24ab328 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -@@ -571,13 +571,17 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) +@@ -397,13 +397,17 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) switch (hints.codec) { case AV_CODEC_ID_H264: @@ -78684,10 +51428,10 @@ index 8691b086a46fcdd03eee809a53ea9b20f74dcc05..b4e2c57d406297f75c5dfc0217f4d335 break; case AV_CODEC_ID_H263: diff --git a/xbmc/cores/omxplayer/OMXVideo.cpp b/xbmc/cores/omxplayer/OMXVideo.cpp -index b2bb0a832f5a722bb9de2a48e21e96d5d74e71b8..f8f26a891f6610de83ec143ec4b51f0aea5424de 100644 +index 311dd6689236d660919c4c4483c51dca2752514a..536332c43e22ccb229e72b88518e54dd8a23ac41 100644 --- a/xbmc/cores/omxplayer/OMXVideo.cpp +++ b/xbmc/cores/omxplayer/OMXVideo.cpp -@@ -401,6 +401,7 @@ bool COMXVideo::Open(CDVDStreamInfo &hints, OMXClock *clock, EDEINTERLACEMODE de +@@ -398,6 +398,7 @@ bool COMXVideo::Open(CDVDStreamInfo &hints, OMXClock *clock, bool hdmi_clock_syn switch (hints.codec) { case AV_CODEC_ID_H264: @@ -78695,7 +51439,7 @@ index b2bb0a832f5a722bb9de2a48e21e96d5d74e71b8..f8f26a891f6610de83ec143ec4b51f0a { switch(hints.profile) { -@@ -437,10 +438,13 @@ bool COMXVideo::Open(CDVDStreamInfo &hints, OMXClock *clock, EDEINTERLACEMODE de +@@ -434,10 +435,13 @@ bool COMXVideo::Open(CDVDStreamInfo &hints, OMXClock *clock, bool hdmi_clock_syn break; } } @@ -78711,10 +51455,10 @@ index b2bb0a832f5a722bb9de2a48e21e96d5d74e71b8..f8f26a891f6610de83ec143ec4b51f0a break; case AV_CODEC_ID_MPEG4: -From 25afb65c978ae78c35cfcfd10cb355ba88d42f7a Mon Sep 17 00:00:00 2001 +From b8c71a30f6d8625f52099abcb71d24fe60a5e250 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Thu, 24 Mar 2016 13:02:58 +0000 -Subject: [PATCH 50/67] ffmpeg: mvc: fix for pixelation from packets with no +Subject: [PATCH 48/61] ffmpeg: mvc: fix for pixelation from packets with no pts/dts --- @@ -78776,10 +51520,10 @@ index 92d9437b36eaa4e655990f7e68634e0bbf4d9605..99f375ba5d5b40eecdd423ac5787276e cd $(PLATFORM);\ CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" CPPFLAGS="$(CPPFLAGS)" LDFLAGS="$(LDFLAGS)" \ -From bcc3e1b01501c7ca65525ae31ecdb7a6028f8e84 Mon Sep 17 00:00:00 2001 +From e6e26007a7508bb472e8da389a0718a8c33515b3 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Wed, 9 Mar 2016 13:08:44 +0000 -Subject: [PATCH 51/67] stereoscopicmanager: remove hardwarebased for rbp +Subject: [PATCH 49/61] stereoscopicmanager: remove hardwarebased for rbp --- xbmc/guilib/StereoscopicsManager.cpp | 2 ++ @@ -78801,10 +51545,10 @@ index 6eb0752994bc5f8c47efbbf211120af0a0720d0c..9426604f6460651f54cc035476e69530 { "mvc_rl", RENDER_STEREO_MODE_SPLIT_HORIZONTAL }, // fallback {} -From 5ca0d3a5d247af35d48a4375131117466ad56f09 Mon Sep 17 00:00:00 2001 +From 6a0689238dba27ebab5eb725bc1347e0cf54f653 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Tue, 17 May 2016 19:24:08 +0100 -Subject: [PATCH 52/67] stereoscopics: Switch to using block_lr for mvc to +Subject: [PATCH 50/61] stereoscopics: Switch to using block_lr for mvc to match makemkv See: http://forum.kodi.tv/showthread.php?tid=221407&pid=2339656#pid2339656 @@ -78817,10 +51561,10 @@ See: http://forum.kodi.tv/showthread.php?tid=221407&pid=2339656#pid2339656 5 files changed, 12 insertions(+), 17 deletions(-) diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -index b4e2c57d406297f75c5dfc0217f4d33507cb6755..470083b2256d23488ca476cebfe8d3ef9f62377e 100644 +index a253b7fe8c591ba318958ea133355febb24ab328..1bab467cee97cad4a05fec71f29ca72d3ca93581 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -@@ -581,7 +581,7 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) +@@ -407,7 +407,7 @@ bool CMMALVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) m_codingType = MMAL_ENCODING_MVC; m_pFormatName= "mmal-mvc"; if (hints.stereo_mode == "mono") @@ -78830,10 +51574,10 @@ index b4e2c57d406297f75c5dfc0217f4d33507cb6755..470083b2256d23488ca476cebfe8d3ef break; case AV_CODEC_ID_H263: diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -index 54e4d0b66680a08c1e4c1be343fabe4371aec6af..5798ba2ede172c89d18b6997874117301a8b6a37 100644 +index 65d998f65493c1b463a4d1cabf36a16c9a06d498..815dc7589fed03a5d448297df5ebddd24daef80d 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp -@@ -1387,7 +1387,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) +@@ -1400,7 +1400,7 @@ CDemuxStream* CDVDDemuxFFmpeg::AddStream(int streamIdx) CDVDInputStreamBluray *bluRay = static_cast<CDVDInputStreamBluray*>(m_pInput); if (bluRay->HasMVC()) { @@ -78873,10 +51617,10 @@ index 04ceed1504c2d81aaa165d232e128c410b9fdc2c..49f7f7ca7e144a259f6d06bd11cd97aa std::string res = convert[mode]; if(res.empty()) diff --git a/xbmc/cores/omxplayer/OMXVideo.cpp b/xbmc/cores/omxplayer/OMXVideo.cpp -index f8f26a891f6610de83ec143ec4b51f0aea5424de..de15bfff05d23949d6e6f4304b15aa7d79120dc2 100644 +index 536332c43e22ccb229e72b88518e54dd8a23ac41..39bc0530cecd54ae8c3a5481c92f1a6a18a4d9c5 100644 --- a/xbmc/cores/omxplayer/OMXVideo.cpp +++ b/xbmc/cores/omxplayer/OMXVideo.cpp -@@ -444,7 +444,7 @@ bool COMXVideo::Open(CDVDStreamInfo &hints, OMXClock *clock, EDEINTERLACEMODE de +@@ -441,7 +441,7 @@ bool COMXVideo::Open(CDVDStreamInfo &hints, OMXClock *clock, bool hdmi_clock_syn m_codingType = OMX_VIDEO_CodingMVC; m_video_codec_name = "omx-mvc"; if (hints.stereo_mode == "mono") @@ -78910,10 +51654,10 @@ index 9426604f6460651f54cc035476e69530b2ea8493..cc929b599125a44ac128713fd4331782 }; -From 0a3a48ddcd0cbcd263105f844d27afa720da9bf2 Mon Sep 17 00:00:00 2001 +From e687fbce1615c87f03cb02f73482e4eda9a0f669 Mon Sep 17 00:00:00 2001 From: Anton Fedchin <anightik@gmail.com> Date: Thu, 10 Mar 2016 18:11:33 +0300 -Subject: [PATCH 53/67] fixup! Revert supporting crappy tab/sbs subtitles. this +Subject: [PATCH 51/61] fixup! Revert supporting crappy tab/sbs subtitles. this fixes regular subtitles. --- @@ -78958,10 +51702,10 @@ index 3a080d06c90b0762482816928642e6de7810b539..7c0b70777556ac7694e7fc511cd4bb18 } -From 49a3522fd02f0d6e4adb10ec413df1bf5e181421 Mon Sep 17 00:00:00 2001 +From 677c4dc68110455444a13ab76dae151fc4f0fc85 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Tue, 10 Feb 2015 15:29:16 +0000 -Subject: [PATCH 54/67] [libcec] Add repeating keypress patch from popcornmix' +Subject: [PATCH 52/61] [libcec] Add repeating keypress patch from popcornmix' repo --- @@ -79848,10 +52592,10 @@ index 0000000000000000000000000000000000000000..8366a696562a934144cc9a21ea6f2cab +1.9.1 + -From fcfb4a5068565c3ca935cf16932f6f45f34a33d0 Mon Sep 17 00:00:00 2001 +From 75ca9806598f9ea98b1e872f68cd8dc899e9ec74 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Sat, 19 Mar 2016 17:15:29 +0000 -Subject: [PATCH 55/67] cec: hack: pretend bump to 3.1.0 +Subject: [PATCH 53/61] cec: hack: pretend bump to 3.1.0 --- tools/depends/target/libcec/Makefile | 1 + @@ -79899,32 +52643,23 @@ index 0000000000000000000000000000000000000000..9e55e51068e7befd9d4ff003156ce1ff + # cec-client + add_subdirectory(src/cec-client) -From 5dc7976451fc1ab8c7aeac2d9b4090a71e5a857d Mon Sep 17 00:00:00 2001 +From 1ca2f1145a8b3baeaee694ce8bd83e76be117cc7 Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Tue, 28 Oct 2014 00:19:40 +0000 -Subject: [PATCH 56/67] [cec] Add settings for configuring button repeats +Subject: [PATCH 54/61] [cec] Add settings for configuring button repeats --- - addons/resource.language.en_gb/resources/strings.po | 17 +++++++++++++++-- + addons/resource.language.en_gb/resources/strings.po | 15 +++++++++++++++ system/peripherals.xml | 4 +++- xbmc/peripherals/devices/PeripheralCecAdapter.cpp | 16 ++++++++++++++++ - 3 files changed, 34 insertions(+), 3 deletions(-) + 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po -index 8cb9f8503c29c54cd0cb55018f867a45248c649f..a4c4387b0a78e4dc9ed875e72c4ce72dd2741fe2 100644 +index b5ae4dc1a6b21ba96fd3498baff1b63004fa6902..cb886deeceb95df1706a1176619944911d5bb64a 100644 --- a/addons/resource.language.en_gb/resources/strings.po +++ b/addons/resource.language.en_gb/resources/strings.po -@@ -19392,8 +19392,6 @@ msgctxt "#38111" - msgid "This category contains other settings for the GUI interface" - msgstr "" - --#empty strings from id 38112 to 38999 -- - #: system/settings/settings.xml - msgctxt "#39000" - msgid "HD and up" -@@ -19414,6 +19412,21 @@ msgctxt "#39003" - msgid "Accelerate h264" +@@ -19480,6 +19480,21 @@ msgctxt "#39007" + msgid "This provides access to where picture sources can be added and otherwise managed." msgstr "" +#: system/peripherals.xml @@ -79946,7 +52681,7 @@ index 8cb9f8503c29c54cd0cb55018f867a45248c649f..a4c4387b0a78e4dc9ed875e72c4ce72d msgid "Extract thumbnails from video files" msgstr "" diff --git a/system/peripherals.xml b/system/peripherals.xml -index ec3c3fe39db5f2272b3a9e49b34de3a4a063aab0..c3dbae029d397ab2e6948296df64b7a6f174b2af 100644 +index b9c8e9d658cca961a4970ab33aa4d221f2435dda..43397c44833c1068c3586eb05039bbd644c93c9b 100644 --- a/system/peripherals.xml +++ b/system/peripherals.xml @@ -31,7 +31,9 @@ @@ -79961,10 +52696,10 @@ index ec3c3fe39db5f2272b3a9e49b34de3a4a063aab0..c3dbae029d397ab2e6948296df64b7a6 <peripheral vendor_product="2548:1001,2548:1002" bus="usb" name="Pulse-Eight CEC Adapter" mapTo="cec"> diff --git a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp -index f784bded97de9491d3eaaee2fb6efc86e74dd07b..8ab327c34e08a14c598b758a67384f1c6a838e6c 100644 +index e6bcbce6911a1714e129ecd5aceead94769231f4..19b3c37bc18fcab30920b12902e8c3397a69dccc 100644 --- a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp +++ b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp -@@ -1284,6 +1284,20 @@ void CPeripheralCecAdapter::SetConfigurationFromLibCEC(const CEC::libcec_configu +@@ -1287,6 +1287,20 @@ void CPeripheralCecAdapter::SetConfigurationFromLibCEC(const CEC::libcec_configu m_configuration.bSendInactiveSource = config.bSendInactiveSource; bChanged |= SetSetting("send_inactive_source", m_configuration.bSendInactiveSource == 1); @@ -79985,7 +52720,7 @@ index f784bded97de9491d3eaaee2fb6efc86e74dd07b..8ab327c34e08a14c598b758a67384f1c m_configuration.iFirmwareVersion = config.iFirmwareVersion; m_configuration.bShutdownOnStandby = config.bShutdownOnStandby; -@@ -1388,6 +1402,8 @@ void CPeripheralCecAdapter::SetConfigurationFromSettings(void) +@@ -1391,6 +1405,8 @@ void CPeripheralCecAdapter::SetConfigurationFromSettings(void) // backwards compatibility. will be removed once the next major release of libCEC is out m_configuration.iDoubleTapTimeoutMs = GetSettingInt("double_tap_timeout_ms"); #endif @@ -79995,20 +52730,20 @@ index f784bded97de9491d3eaaee2fb6efc86e74dd07b..8ab327c34e08a14c598b758a67384f1c if (GetSettingBool("pause_playback_on_deactivate")) { -From c43daf2021b96de898d3522b5248108f9d9af488 Mon Sep 17 00:00:00 2001 +From 0ad79428d9636283d7dd952363050fac2e55898e Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Mon, 3 Nov 2014 23:17:46 +0000 -Subject: [PATCH 57/67] [cec] Don't discard buttons when repeat mode is enabled +Subject: [PATCH 55/61] [cec] Don't discard buttons when repeat mode is enabled --- xbmc/peripherals/devices/PeripheralCecAdapter.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp -index 8ab327c34e08a14c598b758a67384f1c6a838e6c..8b04a37a803c2f0ff15de35a10186e3dc9c0d130 100644 +index 19b3c37bc18fcab30920b12902e8c3397a69dccc..f859f44f6d5379154317b5760d7df720f0894e0d 100644 --- a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp +++ b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp -@@ -776,7 +776,10 @@ void CPeripheralCecAdapter::PushCecKeypress(const CecButtonPress &key) +@@ -778,7 +778,10 @@ void CPeripheralCecAdapter::PushCecKeypress(const CecButtonPress &key) CLog::Log(LOGDEBUG, "%s - received key %2x duration %d", __FUNCTION__, key.iButton, key.iDuration); CSingleLock lock(m_critSection); @@ -80021,20 +52756,20 @@ index 8ab327c34e08a14c598b758a67384f1c6a838e6c..8b04a37a803c2f0ff15de35a10186e3d if (m_currentButton.iButton == key.iButton && m_currentButton.iDuration == 0) { -From 8e198d48296f237f20faa59de880eaef75752459 Mon Sep 17 00:00:00 2001 +From 93c60a7a5fd00d2672b098dbad4a6eab8d2fc8be Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Tue, 4 Nov 2014 18:50:00 +0000 -Subject: [PATCH 58/67] [cec] Temp - more logging +Subject: [PATCH 56/61] [cec] Temp - more logging --- xbmc/peripherals/devices/PeripheralCecAdapter.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp -index 8b04a37a803c2f0ff15de35a10186e3dc9c0d130..259649721512e744fd89bfe66af6bc6324c82653 100644 +index f859f44f6d5379154317b5760d7df720f0894e0d..f1c3a6d242183507c4ce9ebf4651b0c0f7e9c5c9 100644 --- a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp +++ b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp -@@ -773,12 +773,15 @@ void CPeripheralCecAdapter::GetNextKey(void) +@@ -775,12 +775,15 @@ void CPeripheralCecAdapter::GetNextKey(void) void CPeripheralCecAdapter::PushCecKeypress(const CecButtonPress &key) { @@ -80051,7 +52786,7 @@ index 8b04a37a803c2f0ff15de35a10186e3dc9c0d130..259649721512e744fd89bfe66af6bc63 if (m_configuration.iButtonRepeatRateMs == 0 && key.iDuration > 0) { if (m_currentButton.iButton == key.iButton && m_currentButton.iDuration == 0) -@@ -787,6 +790,7 @@ void CPeripheralCecAdapter::PushCecKeypress(const CecButtonPress &key) +@@ -789,6 +792,7 @@ void CPeripheralCecAdapter::PushCecKeypress(const CecButtonPress &key) if (m_bHasButton) m_currentButton.iDuration = key.iDuration; // ignore this one, since it's already been handled by xbmc @@ -80059,7 +52794,7 @@ index 8b04a37a803c2f0ff15de35a10186e3dc9c0d130..259649721512e744fd89bfe66af6bc63 return; } // if we received a keypress with a duration set, try to find the same one without a duration set, and replace it -@@ -797,6 +801,7 @@ void CPeripheralCecAdapter::PushCecKeypress(const CecButtonPress &key) +@@ -799,6 +803,7 @@ void CPeripheralCecAdapter::PushCecKeypress(const CecButtonPress &key) if ((*it).iDuration == 0) { // replace this entry @@ -80067,7 +52802,7 @@ index 8b04a37a803c2f0ff15de35a10186e3dc9c0d130..259649721512e744fd89bfe66af6bc63 (*it).iDuration = key.iDuration; return; } -@@ -806,6 +811,7 @@ void CPeripheralCecAdapter::PushCecKeypress(const CecButtonPress &key) +@@ -808,6 +813,7 @@ void CPeripheralCecAdapter::PushCecKeypress(const CecButtonPress &key) } } @@ -80076,10 +52811,10 @@ index 8b04a37a803c2f0ff15de35a10186e3dc9c0d130..259649721512e744fd89bfe66af6bc63 } -From d61469373a92dbcb58bc8e38fc8d921106f61943 Mon Sep 17 00:00:00 2001 +From 8bc97ca506489e1f77baf7a4b978971caac9d42c Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Fri, 22 Jan 2016 12:29:41 +0000 -Subject: [PATCH 59/67] [cec] Update for libcec 3.1.0 +Subject: [PATCH 57/61] [cec] Update for libcec 3.1.0 --- configure.ac | 4 ++-- @@ -80087,7 +52822,7 @@ Subject: [PATCH 59/67] [cec] Update for libcec 3.1.0 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac -index d498f958b83813cbf5fce0a86bf07743665b5ed4..277c97f72b20650ba6a594e6363b9a863e0310a8 100644 +index 5b8c04b246ac91b0a9cf7d11659ac9726c1a80ed..5c99e8288d925c6f7499ea969783c2d6f1d3aba5 100644 --- a/configure.ac +++ b/configure.ac @@ -1433,9 +1433,9 @@ if test "x$use_libcec" != "xno"; then @@ -80103,7 +52838,7 @@ index d498f958b83813cbf5fce0a86bf07743665b5ed4..277c97f72b20650ba6a594e6363b9a86 if test "x$use_libcec" != "xno"; then diff --git a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp -index 259649721512e744fd89bfe66af6bc6324c82653..ae7fd02ea17cb11318083f853d6b1641af4ecadb 100644 +index f1c3a6d242183507c4ce9ebf4651b0c0f7e9c5c9..28a6a8148810da940f977976a627018c59a719db 100644 --- a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp +++ b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp @@ -43,7 +43,7 @@ using namespace PERIPHERALS; @@ -80115,7 +52850,7 @@ index 259649721512e744fd89bfe66af6bc6324c82653..ae7fd02ea17cb11318083f853d6b1641 /* time in seconds to ignore standby commands from devices after the screensaver has been activated */ #define SCREENSAVER_TIMEOUT 20 -@@ -1326,7 +1326,7 @@ void CPeripheralCecAdapter::SetConfigurationFromLibCEC(const CEC::libcec_configu +@@ -1329,7 +1329,7 @@ void CPeripheralCecAdapter::SetConfigurationFromLibCEC(const CEC::libcec_configu void CPeripheralCecAdapter::SetConfigurationFromSettings(void) { // client version matches the version of libCEC that we originally used the API from @@ -80125,10 +52860,10 @@ index 259649721512e744fd89bfe66af6bc6324c82653..ae7fd02ea17cb11318083f853d6b1641 // device name 'XBMC' snprintf(m_configuration.strDeviceName, 13, "%s", GetSettingString("device_name").c_str()); -From f50610a41e776cb15acbb2740587cf65b47811d0 Mon Sep 17 00:00:00 2001 +From 333e05a9c5e21d95f09b32858a6c5587e2d9beed Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Sat, 19 Mar 2016 14:46:41 +0000 -Subject: [PATCH 60/67] libcec: use system audio mode request instead of power +Subject: [PATCH 58/61] libcec: use system audio mode request instead of power on to start AVR reliable --- @@ -80194,10 +52929,10 @@ index 39ba882d0c7e270b4d1d1d566027cbaffb76b587..4565dc9f6fc0b3e6b49133443c19e107 $(LIBDYLIB): $(PLATFORM) -From b3074634af438e1dd9de238718364d82d4ee46e2 Mon Sep 17 00:00:00 2001 +From a9f40d9bf8aae676de620b2cd934ddbc1d202974 Mon Sep 17 00:00:00 2001 From: Rainer Hochecker <fernetmenta@online.de> Date: Tue, 22 Mar 2016 09:51:52 +0100 -Subject: [PATCH 61/67] python: use kodi provided cert if available +Subject: [PATCH 59/61] python: use kodi provided cert if available --- xbmc/interfaces/python/XBPython.cpp | 7 +++++-- @@ -80223,10 +52958,10 @@ index d762bf4f8fdca2a1081026089977ae8987c88b66..ff4ed7db26845905108ea0ae504e4f58 if (PyEval_ThreadsInitialized()) -From bd545157e573f1904ac552693524a4bce8789c5d Mon Sep 17 00:00:00 2001 +From 1dc7050d2ea538674cf19aadf23718e1d392560f Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> Date: Wed, 25 May 2016 18:31:17 +0100 -Subject: [PATCH 62/67] rbp: Hard code the number of buffers to improve audio +Subject: [PATCH 60/61] rbp: Hard code the number of buffers to improve audio sync --- @@ -80235,7 +52970,7 @@ Subject: [PATCH 62/67] rbp: Hard code the number of buffers to improve audio 2 files changed, 10 insertions(+) diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml -index 2e6c903df5e4d2cd064466db0ef55deada5cdc80..29d8f92c123875a83eae4832c1f6246a6deefc3c 100644 +index b7770ebc1b9568f9fe141d90a118b87106c86735..507dd61a464510760112a009d73bdc63cab19e4b 100644 --- a/system/settings/rbp.xml +++ b/system/settings/rbp.xml @@ -92,6 +92,12 @@ @@ -80252,10 +52987,10 @@ index 2e6c903df5e4d2cd064466db0ef55deada5cdc80..29d8f92c123875a83eae4832c1f6246a <category id="audio"> <group id="1"> diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp -index db537d33a5d55fc856bbd3ec0a7846df3bb060be..ee34c0b31da3b05fabae5e47ad51db2f09e682c3 100644 +index f2a133e1ff7b440ebc741878ccf87e6da090aa8c..e577d03b8280285567af0d332bc2284f6ffbf71a 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp +++ b/xbmc/cores/VideoPlayer/VideoRenderers/RenderManager.cpp -@@ -1066,7 +1066,11 @@ void CRenderManager::UpdateDisplayLatency() +@@ -1062,7 +1062,11 @@ void CRenderManager::UpdateDisplayLatency() refresh = 0; // No idea about refresh rate when windowed, just get the default latency m_displayLatency = (double) g_advancedSettings.GetDisplayLatency(refresh); @@ -80268,347 +53003,70 @@ index db537d33a5d55fc856bbd3ec0a7846df3bb060be..ee34c0b31da3b05fabae5e47ad51db2f } -From cb6cdf5bf5a392fffc7e58631a4767ab8836ea02 Mon Sep 17 00:00:00 2001 +From c60cda47009f0431a2f2dc1764882d8b1e5e7acd Mon Sep 17 00:00:00 2001 From: popcornmix <popcornmix@gmail.com> -Date: Wed, 8 Jun 2016 01:11:26 +0100 -Subject: [PATCH 63/67] omxvideo: Remove call to AutoInterlaceMethod. Treat - auto as advanced +Date: Mon, 4 Jul 2016 18:30:03 +0100 +Subject: [PATCH 61/61] rbp: Update the GL libs to new naming scheme +As the opensource mesa GL library is getting more usable, the name collision wih the firmware GL driver is causing issues. +As such we are renaming the firmware GL driver to avoid this. + +The new names are libbrcmEGL.so and libbrcmGLESv2.so. Both will be supported for some time, but the original name +will be dropped at some point --- - xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp | 2 +- - xbmc/cores/omxplayer/OMXVideo.cpp | 5 ++++- - 2 files changed, 5 insertions(+), 2 deletions(-) + configure.ac | 2 +- + project/cmake/modules/FindOpenGLES.cmake | 6 +++--- + tools/depends/configure.ac | 2 +- + 3 files changed, 5 insertions(+), 5 deletions(-) -diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp -index d65857779628debfc85b47b8dd283513edb5a319..523e52c27de2711ca03c6b06767c940be6e3d177 100644 ---- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp -+++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp -@@ -632,7 +632,7 @@ bool CMMALRenderer::Supports(ESCALINGMETHOD method) +diff --git a/configure.ac b/configure.ac +index 5c99e8288d925c6f7499ea969783c2d6f1d3aba5..54b9552f8ee5c2dc8bace2337a0254b5e5191fee 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -929,7 +929,7 @@ if test "$use_gles" = "yes"; then + AC_DEFINE([HAVE_LIBEGL],[1],["Define to 1 if you have the `EGL' library (-lEGL)."]) + AC_DEFINE([HAVE_LIBGLESV2],[1],["Define to 1 if you have the `GLESv2' library (-lGLESv2)."]) + AC_MSG_RESULT(== WARNING: OpenGLES support is assumed.) +- LIBS="$LIBS -lEGL -lGLESv2 -lbcm_host -lvcos -lvchiq_arm -lmmal -lmmal_core -lmmal_util -lvcsm" ++ LIBS="$LIBS -lbrcmEGL -lbrcmGLESv2 -lbcm_host -lvcos -lvchiq_arm -lmmal -lmmal_core -lmmal_util -lvcsm" + else + AC_CHECK_LIB([EGL], [main],, AC_MSG_ERROR($missing_library)) + AC_CHECK_LIB([GLESv2],[main],, AC_MSG_ERROR($missing_library)) +diff --git a/project/cmake/modules/FindOpenGLES.cmake b/project/cmake/modules/FindOpenGLES.cmake +index 5d71dd4ad34de4d4bb3a4f24198c86c82ebca2d4..4c1cba7a85c32140e9ebf4c766e845b2e97f769a 100644 +--- a/project/cmake/modules/FindOpenGLES.cmake ++++ b/project/cmake/modules/FindOpenGLES.cmake +@@ -13,7 +13,7 @@ + find_package(EMBEDDED) - EINTERLACEMETHOD CMMALRenderer::AutoInterlaceMethod() - { -- return m_sourceWidth * m_sourceHeight <= 576 * 720 ? VS_INTERLACEMETHOD_MMAL_ADVANCED : VS_INTERLACEMETHOD_MMAL_BOB; -+ return VS_INTERLACEMETHOD_MMAL_ADVANCED; - } + if(PKG_CONFIG_FOUND AND NOT PLATFORM STREQUAL "raspberry-pi") +- pkg_check_modules(PC_OPENGLES glesv2) ++ pkg_check_modules(PC_OPENGLES brcmglesv2) + if(NOT OPENGLES_FOUND AND EMBEDDED_FOUND) + set(CMAKE_PREFIX_PATH ${EMBEDDED_FOUND} ${CMAKE_PREFIX_PATH}) + endif() +@@ -22,9 +22,9 @@ endif() + if(NOT CORE_SYSTEM_NAME STREQUAL ios) + find_path(OPENGLES_INCLUDE_DIR GLES2/gl2.h + PATHS ${PC_OPENGLES_INCLUDEDIR}) +- find_library(OPENGLES_gl_LIBRARY NAMES GLESv2 ++ find_library(OPENGLES_gl_LIBRARY NAMES brcmGLESv2 + PATHS ${PC_OPENGLES_LIBDIR}) +- find_library(OPENGLES_egl_LIBRARY NAMES EGL ++ find_library(OPENGLES_egl_LIBRARY NAMES brcmEGL + PATHS ${PC_OPENGLES_LIBDIR}) + else() + find_library(OPENGLES_gl_LIBRARY NAMES OpenGLES +diff --git a/tools/depends/configure.ac b/tools/depends/configure.ac +index fb0bd6dad18199e8893c38644f93659bf0a3f61b..010288dc5de74380fc3795d00dbd99847cf2ed3e 100644 +--- a/tools/depends/configure.ac ++++ b/tools/depends/configure.ac +@@ -390,7 +390,7 @@ if test "$target_platform" = "raspberry-pi" ; then + -isystem${use_firmware}/opt/vc/include \ + -isystem${use_firmware}/opt/vc/include/interface/vcos/pthreads \ + -isystem${use_firmware}/opt/vc/include/interface/vmcs_host/linux" +- platform_ldflags+=" -L${use_firmware}/opt/vc/lib -lEGL -lGLESv2 -lbcm_host -lvcos \ ++ platform_ldflags+=" -L${use_firmware}/opt/vc/lib -lbrcmEGL -lbrcmGLESv2 -lbcm_host -lvcos \ + -lvchiq_arm" + fi - void CMMALRenderer::SetVideoRect(const CRect& InSrcRect, const CRect& InDestRect) -diff --git a/xbmc/cores/omxplayer/OMXVideo.cpp b/xbmc/cores/omxplayer/OMXVideo.cpp -index de15bfff05d23949d6e6f4304b15aa7d79120dc2..79685835382422d0a22d7b75d7c1408e2c053403 100644 ---- a/xbmc/cores/omxplayer/OMXVideo.cpp -+++ b/xbmc/cores/omxplayer/OMXVideo.cpp -@@ -242,7 +242,10 @@ bool COMXVideo::PortSettingsChanged(ResolutionUpdateInfo &resinfo) - - if(m_deinterlace) - { -- EINTERLACEMETHOD interlace_method = m_renderManager.AutoInterlaceMethod(CMediaSettings::GetInstance().GetCurrentVideoSettings().m_InterlaceMethod); -+ EINTERLACEMETHOD interlace_method = CMediaSettings::GetInstance().GetCurrentVideoSettings().m_InterlaceMethod; -+ if (interlace_method == VS_INTERLACEMETHOD_AUTO) -+ interlace_method = VS_INTERLACEMETHOD_MMAL_ADVANCED; -+ - bool advanced_deinterlace = interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED || interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED_HALF; - bool half_framerate = interlace_method == VS_INTERLACEMETHOD_MMAL_ADVANCED_HALF || interlace_method == VS_INTERLACEMETHOD_MMAL_BOB_HALF; - - -From 120051ba33cc7dc2885b3bf3abf49c4903bee0f8 Mon Sep 17 00:00:00 2001 -From: popcornmix <popcornmix@gmail.com> -Date: Wed, 15 Jun 2016 23:41:43 +0100 -Subject: [PATCH 64/67] mmal_codec: Use EOS through codec to determine drain is - complete - -Rather than relying on a timeout from codec, feed an EOS through to ensure all frames have been returned ---- - .../VideoPlayer/DVDCodecs/Video/MMALCodec.cpp | 72 ++++++++++++++-------- - xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.h | 3 + - 2 files changed, 49 insertions(+), 26 deletions(-) - -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -index 470083b2256d23488ca476cebfe8d3ef9f62377e..cd0d30d77cc1cd8803ccde317bcc2f3cd61000e4 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -@@ -117,6 +117,9 @@ CMMALVideo::CMMALVideo(CProcessInfo &processInfo) : CDVDVideoCodec(processInfo) - m_fps = 0.0f; - m_num_decoded = 0; - m_codecControlFlags = 0; -+ m_got_eos = false; -+ m_packet_num = 0; -+ m_packet_num_eos = ~0; - } - - CMMALVideo::~CMMALVideo() -@@ -243,7 +246,7 @@ void CMMALVideo::dec_output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf - { - if (!(buffer->cmd == 0 && buffer->length > 0)) - if (g_advancedSettings.CanLogComponent(LOGVIDEO)) -- CLog::Log(LOGDEBUG, "%s::%s port:%p buffer %p, len %d cmd:%x", CLASSNAME, __func__, port, buffer, buffer->length, buffer->cmd); -+ CLog::Log(LOGDEBUG, "%s::%s port:%p buffer %p, len %d cmd:%x flags:%x", CLASSNAME, __func__, port, buffer, buffer->length, buffer->cmd, buffer->flags); - - bool kept = false; - -@@ -288,6 +291,12 @@ void CMMALVideo::dec_output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf - kept = true; - } - } -+ if (buffer->flags & MMAL_BUFFER_HEADER_FLAG_EOS) -+ { -+ CSingleLock lock(m_output_mutex); -+ m_got_eos = true; -+ m_output_cond.notifyAll(); -+ } - } - else if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED) - { -@@ -790,11 +799,18 @@ int CMMALVideo::Decode(uint8_t* pData, int iSize, double dts, double pts) - - MMAL_BUFFER_HEADER_T *buffer; - MMAL_STATUS_T status; -- -+ bool drain = (m_codecControlFlags & DVD_CODEC_CTRL_DRAIN) ? true : false; -+ bool send_eos = drain && !m_got_eos && m_packet_num_eos != m_packet_num; -+ // we don't get an EOS response if no packets have been sent -+ if (m_packet_num == 0) -+ { -+ send_eos = false; -+ m_got_eos = true; -+ } - Prime(); - while (1) - { -- if (pData) -+ if (pData || send_eos) - { - // 500ms timeout - { -@@ -817,17 +833,25 @@ int CMMALVideo::Decode(uint8_t* pData, int iSize, double dts, double pts) - if (m_dropState) - buffer->flags |= MMAL_BUFFER_HEADER_FLAG_USER3; - -- memcpy(buffer->data, pData, buffer->length); -+ if (pData) -+ memcpy(buffer->data, pData, buffer->length); - iSize -= buffer->length; - pData += buffer->length; - - if (iSize == 0) -+ { -+ m_packet_num++; - buffer->flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_END; -- -+ if (send_eos) -+ { -+ buffer->flags |= MMAL_BUFFER_HEADER_FLAG_EOS; -+ m_packet_num_eos = m_packet_num; -+ m_got_eos = false; -+ } -+ } - if (g_advancedSettings.CanLogComponent(LOGVIDEO)) - CLog::Log(LOGDEBUG, "%s::%s - %-8p %-6d/%-6d dts:%.3f pts:%.3f flags:%x ready_queue(%d)", - CLASSNAME, __func__, buffer, buffer->length, iSize, dts == DVD_NOPTS_VALUE ? 0.0 : dts*1e-6, pts == DVD_NOPTS_VALUE ? 0.0 : pts*1e-6, buffer->flags, m_output_ready.size()); -- assert((int)buffer->length > 0); - status = mmal_port_send_buffer(m_dec_input, buffer); - if (status != MMAL_SUCCESS) - { -@@ -879,36 +903,28 @@ int CMMALVideo::Decode(uint8_t* pData, int iSize, double dts, double pts) - bool full = queued > DVD_MSEC_TO_TIME(1000); - int ret = 0; - -- unsigned int pics = m_output_ready.size(); -- if (m_preroll && (pics >= GetAllowedReferences() || m_codecControlFlags & DVD_CODEC_CTRL_DRAIN)) -- m_preroll = false; -- if (pics > 0 && !m_preroll) -- ret |= VC_PICTURE; -- if ((m_preroll || pics <= 1) && mmal_queue_length(m_dec_input_pool->queue) > 0 && !(m_codecControlFlags & DVD_CODEC_CTRL_DRAIN)) -- ret |= VC_BUFFER; -- -- bool slept = false; -- if (!ret) -+ XbmcThreads::EndTime delay(500); -+ while (!ret && !delay.IsTimePast()) - { -- slept = true; -+ unsigned int pics = m_output_ready.size(); -+ if (m_preroll && (pics >= GetAllowedReferences() || drain)) -+ m_preroll = false; -+ if (pics > 0 && !m_preroll) -+ ret |= VC_PICTURE; -+ if ((m_preroll || pics <= 1) && mmal_queue_length(m_dec_input_pool->queue) > 0 && (!drain || m_got_eos || m_packet_num_eos != m_packet_num)) -+ ret |= VC_BUFFER; -+ if (!ret) - { - // otherwise we busy spin - lock.Leave(); - CSingleLock output_lock(m_output_mutex); -- m_output_cond.wait(output_lock, 30); -+ m_output_cond.wait(output_lock, delay.MillisLeft()); - lock.Enter(); - } -- unsigned int pics = m_output_ready.size(); -- if (m_preroll && (pics >= GetAllowedReferences() || m_codecControlFlags & DVD_CODEC_CTRL_DRAIN)) -- m_preroll = false; -- if (pics > 0 && !m_preroll) -- ret |= VC_PICTURE; -- if ((m_preroll || pics <= 1) && (mmal_queue_length(m_dec_input_pool->queue) > 0 || m_codecControlFlags & DVD_CODEC_CTRL_DRAIN)) -- ret |= VC_BUFFER; - } - - if (g_advancedSettings.CanLogComponent(LOGVIDEO)) -- CLog::Log(LOGDEBUG, "%s::%s - ret(%x) pics(%d) inputs(%d) slept(%d) queued(%.2f) (%.2f:%.2f) full(%d) flags(%x) preroll(%d)", CLASSNAME, __func__, ret, m_output_ready.size(), mmal_queue_length(m_dec_input_pool->queue), slept, queued*1e-6, m_demuxerPts*1e-6, m_decoderPts*1e-6, full, m_codecControlFlags, m_preroll); -+ CLog::Log(LOGDEBUG, "%s::%s - ret(%x) pics(%d) inputs(%d) slept(%2d) queued(%.2f) (%.2f:%.2f) full(%d) flags(%x) preroll(%d) eos(%d %d/%d)", CLASSNAME, __func__, ret, m_output_ready.size(), mmal_queue_length(m_dec_input_pool->queue), 500-delay.MillisLeft(), queued*1e-6, m_demuxerPts*1e-6, m_decoderPts*1e-6, full, m_codecControlFlags, m_preroll, m_got_eos, m_packet_num, m_packet_num_eos); - - return ret; - } -@@ -981,6 +997,10 @@ void CMMALVideo::Reset(void) - m_demuxerPts = DVD_NOPTS_VALUE; - m_codecControlFlags = 0; - m_dropState = false; -+ m_num_decoded = 0; -+ m_got_eos = false; -+ m_packet_num = 0; -+ m_packet_num_eos = ~0; - m_preroll = !m_hints.stills && (m_speed == DVD_PLAYSPEED_NORMAL || m_speed == DVD_PLAYSPEED_PAUSE); - } - -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.h -index d008c6c538819a05be9925ab8cd342b131e511d8..122a5e24f5ffb1bf2415867ec98d8e5104339ab1 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.h -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.h -@@ -134,6 +134,9 @@ protected: - int m_codecControlFlags; - bool m_dropState; - bool m_preroll; -+ bool m_got_eos; -+ uint32_t m_packet_num; -+ uint32_t m_packet_num_eos; - - CCriticalSection m_sharedSection; - MMAL_COMPONENT_T *m_dec; - -From d91a21ae571cc2bf2c5103c8c72fc1262379f4b5 Mon Sep 17 00:00:00 2001 -From: popcornmix <popcornmix@gmail.com> -Date: Fri, 17 Jun 2016 16:23:25 +0100 -Subject: [PATCH 65/67] rbp: Update transposed video scaling to match other - platforms - ---- - .../VideoRenderers/HwDecRender/MMALRenderer.cpp | 29 ++++++++++++++++++---- - xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 29 ++++++++++++++++++---- - 2 files changed, 48 insertions(+), 10 deletions(-) - -diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp -index 523e52c27de2711ca03c6b06767c940be6e3d177..8a4bf24625a57b11908f4f38588fb348581556a6 100644 ---- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp -+++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/MMALRenderer.cpp -@@ -656,11 +656,30 @@ void CMMALRenderer::SetVideoRect(const CRect& InSrcRect, const CRect& InDestRect - // fix up transposed video - if (m_renderOrientation == 90 || m_renderOrientation == 270) - { -- float diff = (DestRect.Height() - DestRect.Width()) * 0.5f; -- DestRect.x1 -= diff; -- DestRect.x2 += diff; -- DestRect.y1 += diff; -- DestRect.y2 -= diff; -+ float newWidth, newHeight; -+ float aspectRatio = GetAspectRatio(); -+ // clamp width if too wide -+ if (DestRect.Height() > DestRect.Width()) -+ { -+ newWidth = DestRect.Width(); // clamp to the width of the old dest rect -+ newHeight = newWidth * aspectRatio; -+ } -+ else // else clamp to height -+ { -+ newHeight = DestRect.Height(); // clamp to the height of the old dest rect -+ newWidth = newHeight / aspectRatio; -+ } -+ -+ // calculate the center point of the view and offsets -+ float centerX = DestRect.x1 + DestRect.Width() * 0.5f; -+ float centerY = DestRect.y1 + DestRect.Height() * 0.5f; -+ float diffX = newWidth * 0.5f; -+ float diffY = newHeight * 0.5f; -+ -+ DestRect.x1 = centerX - diffX; -+ DestRect.x2 = centerX + diffX; -+ DestRect.y1 = centerY - diffY; -+ DestRect.y2 = centerY + diffY; - } - - // check if destination rect or video view mode has changed -diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -index d61dc4f2668f8aca91bce79cfb631034061c491c..ed138297b49c8d3e6b42a1f1fa5fa08bd01be11b 100644 ---- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -@@ -640,11 +640,30 @@ void OMXPlayerVideo::SetVideoRect(const CRect &InSrcRect, const CRect &InDestRec - // fix up transposed video - if (m_hints.orientation == 90 || m_hints.orientation == 270) - { -- float diff = (DestRect.Height() - DestRect.Width()) * 0.5f; -- DestRect.x1 -= diff; -- DestRect.x2 += diff; -- DestRect.y1 += diff; -- DestRect.y2 -= diff; -+ float newWidth, newHeight; -+ float aspectRatio = GetAspectRatio(); -+ // clamp width if too wide -+ if (DestRect.Height() > DestRect.Width()) -+ { -+ newWidth = DestRect.Width(); // clamp to the width of the old dest rect -+ newHeight = newWidth * aspectRatio; -+ } -+ else // else clamp to height -+ { -+ newHeight = DestRect.Height(); // clamp to the height of the old dest rect -+ newWidth = newHeight / aspectRatio; -+ } -+ -+ // calculate the center point of the view and offsets -+ float centerX = DestRect.x1 + DestRect.Width() * 0.5f; -+ float centerY = DestRect.y1 + DestRect.Height() * 0.5f; -+ float diffX = newWidth * 0.5f; -+ float diffY = newHeight * 0.5f; -+ -+ DestRect.x1 = centerX - diffX; -+ DestRect.x2 = centerX + diffX; -+ DestRect.y1 = centerY - diffY; -+ DestRect.y2 = centerY + diffY; - } - - // check if destination rect or video view mode has changed - -From bd128ae3789c33616ae6ebd55fbae13984f98477 Mon Sep 17 00:00:00 2001 -From: popcornmix <popcornmix@gmail.com> -Date: Sun, 19 Jun 2016 16:53:49 +0100 -Subject: [PATCH 66/67] mmalcodec: Add another buffer when deinterlacing - -See: http://forum.kodi.tv/showthread.php?tid=276372 ---- - xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -index cd0d30d77cc1cd8803ccde317bcc2f3cd61000e4..6fd59a64dd48c05d1ccc3183adc5deda16e930a2 100644 ---- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/MMALCodec.cpp -@@ -400,7 +400,7 @@ bool CMMALVideo::CreateDeinterlace(EINTERLACEMETHOD interlace_method) - m_deint_input->userdata = (struct MMAL_PORT_USERDATA_T *)this; - - // Image_fx assumed 3 frames of context. simple deinterlace doesn't require this -- status = mmal_port_parameter_set_uint32(m_deint_input, MMAL_PARAMETER_EXTRA_BUFFERS, GetAllowedReferences() - 5 + advanced_deinterlace ? 2:0); -+ status = mmal_port_parameter_set_uint32(m_deint_input, MMAL_PARAMETER_EXTRA_BUFFERS, 1 + GetAllowedReferences() - 5 + advanced_deinterlace ? 2:0); - if (status != MMAL_SUCCESS) - CLog::Log(LOGERROR, "%s::%s Failed to enable extra buffers on %s (status=%x %s)", CLASSNAME, __func__, m_deint_input->name, status, mmal_status_to_string(status)); - - -From a89d7094bd34a58451effaa3fbbc72651888ea23 Mon Sep 17 00:00:00 2001 -From: popcornmix <popcornmix@gmail.com> -Date: Fri, 1 Jul 2016 13:15:36 +0100 -Subject: [PATCH 67/67] UNSTABLE: This is a placeholder. Commits after this - point are considered experimental. - ---- - .placeholder | 0 - 1 file changed, 0 insertions(+), 0 deletions(-) - create mode 100644 .placeholder - -diff --git a/.placeholder b/.placeholder -new file mode 100644 -index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tools/RPi/rpi-kodi-rebase.sh b/tools/RPi/rpi-kodi-rebase.sh index 85eeeeabce..f16552f05e 100755 --- a/tools/RPi/rpi-kodi-rebase.sh +++ b/tools/RPi/rpi-kodi-rebase.sh @@ -4,7 +4,7 @@ TODO=$1 # Drop commits not used DROP_COMMITS=" -THIS_IS_A_PLACEHOLDER, REPLACE WITH COMMIT DESCRIPTION ONCE THERE IS SOMETHING TO BE DROPPED! +UNSTABLE\: This is a placeholder\. Commits after this point are considered experimental\. " IFS=$'\n'