<commit_before>// Copyright (c) 2017-2018 Intel Corporation
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include "umc_defs.h"
#ifdef MFX_ENABLE_H265_VIDEO_DECODE

#include "umc_h265_mfx_supplier.h"

#include "umc_h265_frame_list.h"
#include "umc_h265_nal_spl.h"
#include "umc_h265_bitstream_headers.h"

#include "umc_h265_dec_defs.h"

#include "vm_sys_info.h"

#include "umc_h265_debug.h"

#include "umc_h265_mfx_utils.h"

namespace UMC_HEVC_DECODER
{

////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////
RawHeader_H265::RawHeader_H265()
{
    Reset();
}

void RawHeader_H265::Reset()
{
    m_id = -1;
    m_buffer.clear();
}

int32_t RawHeader_H265::GetID() const
{
    return m_id;
}

size_t RawHeader_H265::GetSize() const
{
    return m_buffer.size();
}

uint8_t * RawHeader_H265::GetPointer()
{
    return
        m_buffer.empty() ? nullptr : &m_buffer[0];
}

void RawHeader_H265::Resize(int32_t id, size_t newSize)
{
    m_id = id;
    m_buffer.resize(newSize);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////
void RawHeaders_H265::Reset()
{
    m_sps.Reset();
    m_pps.Reset();
}

RawHeader_H265 * RawHeaders_H265::GetSPS()
{
    return &m_sps;
}

RawHeader_H265 * RawHeaders_H265::GetPPS()
{
    return &m_pps;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////
MFXTaskSupplier_H265::MFXTaskSupplier_H265()
    : TaskSupplier_H265()
{
    memset(&m_firstVideoParams, 0, sizeof(mfxVideoParam));
}

MFXTaskSupplier_H265::~MFXTaskSupplier_H265()
{
    Close();
}

// Initialize task supplier
UMC::Status MFXTaskSupplier_H265::Init(UMC::VideoDecoderParams *init)
{
    UMC::Status umcRes;

    if (NULL == init)
        return UMC::UMC_ERR_NULL_PTR;

    Close();

    m_initializationParams = *init;
    m_pMemoryAllocator = init->lpMemoryAllocator;
    m_DPBSizeEx = 0;

    m_sei_messages = new SEI_Storer_H265();
    m_sei_messages->Init();

    int32_t nAllowedThreadNumber = init->numThreads;
    if(nAllowedThreadNumber < 0) nAllowedThreadNumber = 0;

    // calculate number of slice decoders.
    // It should be equal to CPU number
    m_iThreadNum = (0 == nAllowedThreadNumber) ? (vm_sys_info_get_cpu_num()) : (nAllowedThreadNumber);

    umcRes = MVC_Extension::Init();
    if (UMC::UMC_OK != umcRes)
    {
        return umcRes;
    }

    AU_Splitter_H265::Init(init);

    m_pSegmentDecoder = new H265SegmentDecoderBase *[m_iThreadNum];
    memset(m_pSegmentDecoder, 0, sizeof(H265SegmentDecoderBase *) * m_iThreadNum);

    CreateTaskBroker();
    m_pTaskBroker->Init(m_iThreadNum);

    for (uint32_t i = 0; i < m_iThreadNum; i += 1)
    {
        if (UMC::UMC_OK != m_pSegmentDecoder[i]->Init(i))
            return UMC::UMC_ERR_INIT;
    }

    m_local_delta_frame_time = 1.0/30;
    m_frameOrder             = 0;
    m_use_external_framerate = 0 < init->info.framerate;

    if (m_use_external_framerate)
    {
        m_local_delta_frame_time = 1 / init->info.framerate;
    }

    GetView()->dpbSize = 16;
    m_DPBSizeEx = m_iThreadNum + init->info.bitrate;

    return UMC::UMC_OK;
}

// Check whether specified frame has been decoded, and if it was,
// whether it is necessary to display some frame
bool MFXTaskSupplier_H265::CheckDecoding(bool should_additional_check, H265DecoderFrame * outputFrame)
{
    ViewItem_H265 &view = *GetView();

    if (!outputFrame->IsDecodingStarted())
        return false;

    if (outputFrame->IsDecodingCompleted())
    {
        if (!should_additional_check)
            return true;

        int32_t maxReadyUID = outputFrame->m_UID;
        uint32_t inDisplayStage = 0;

        UMC::AutomaticUMCMutex guard(m_mGuard);

        for (H265DecoderFrame * pTmp = view.pDPB->head(); pTmp; pTmp = pTmp->future())
        {
            if (pTmp->m_wasOutputted != 0 && pTmp->m_wasDisplayed == 0 && pTmp->m_maxUIDWhenWasDisplayed)
            {
                inDisplayStage++; // number of outputted frames at this moment
            }

            if ((pTmp->IsDecoded() || pTmp->IsDecodingCompleted()) && maxReadyUID < pTmp->m_UID)
                maxReadyUID = pTmp->m_UID;
        }

        DEBUG_PRINT1((VM_STRING("output frame - %d, notDecoded - %u, count - %u\n"), outputFrame->m_PicOrderCnt, notDecoded, count));
        if (inDisplayStage > 1 || m_maxUIDWhenWasDisplayed <= maxReadyUID)
        {
            return true;
        }
    }

    return false;
}

// Perform decoding task for thread number threadNumber
mfxStatus MFXTaskSupplier_H265::RunThread(mfxU32 threadNumber)
{
    UMC::Status sts = m_pSegmentDecoder[threadNumber]->ProcessSegment();

    if (sts == UMC::UMC_ERR_NOT_ENOUGH_DATA)
        return MFX_TASK_BUSY;
    else if(sts == UMC::UMC_ERR_DEVICE_FAILED)
        return MFX_ERR_DEVICE_FAILED;
    else if (sts == UMC::UMC_ERR_GPU_HANG)
        return MFX_ERR_GPU_HANG;

    if (sts != UMC::UMC_OK)
        return MFX_ERR_UNDEFINED_BEHAVIOR;

    return MFX_TASK_WORKING;
}

// Check whether all slices for the frame were found
void MFXTaskSupplier_H265::CompleteFrame(H265DecoderFrame * pFrame)
{
    if (!pFrame)
        return;

    H265DecoderFrameInfo * slicesInfo = pFrame->GetAU();
    if (slicesInfo->GetStatus() > H265DecoderFrameInfo::STATUS_NOT_FILLED)
        return;

    TaskSupplier_H265::CompleteFrame(pFrame);
}

// Set initial video params from application
void MFXTaskSupplier_H265::SetVideoParams(mfxVideoParam * par)
{
    m_firstVideoParams = *par;
    m_decodedOrder     = m_firstVideoParams.mfx.DecodedOrder != 0;
}

UMC::Status MFXTaskSupplier_H265::FillVideoParam(mfxVideoParam *par, bool full)
{
    const H265SeqParamSet * seq = GetHeaders()->m_SeqParams.GetCurrentHeader();
    if (!seq)
        return UMC::UMC_ERR_FAILED;

    if (MFX_Utility::FillVideoParam(seq, par, full) != UMC::UMC_OK)
        return UMC::UMC_ERR_FAILED;

    return UMC::UMC_OK;
}

// Decode headers nal unit
UMC::Status MFXTaskSupplier_H265::DecodeHeaders(UMC::MediaDataEx *nalUnit)
{
    UMC::Status sts = TaskSupplier_H265::DecodeHeaders(nalUnit);
    if (sts != UMC::UMC_OK)
        return sts;

    {
        // save sps/pps
        uint32_t nal_unit_type = nalUnit->GetExData()->values[0];
        switch(nal_unit_type)
        {
            case NAL_UT_SPS:
            case NAL_UT_PPS:
                {
                    static const uint8_t start_code_prefix[] = {0, 0, 0, 1};
                    size_t const prefix_size = sizeof(start_code_prefix);

                    size_t size = nalUnit->GetDataSize();
                    bool isSPS = (nal_unit_type == NAL_UT_SPS);
                    RawHeader_H265 * hdr = isSPS ? GetSPS() : GetPPS();
                    H265SeqParamSet * currSPS = isSPS ? m_Headers.m_SeqParams.GetCurrentHeader() : nullptr;
                    H265PicParamSet * currPPS = isSPS ? nullptr : m_Headers.m_PicParams.GetCurrentHeader();
                    int32_t id = isSPS ? m_Headers.m_SeqParams.GetCurrentID() : m_Headers.m_PicParams.GetCurrentID();
                    if (hdr->GetPointer() != nullptr)
                    {
                        if (hdr->GetID() == id)
                        {
                            bool changed =
                                size + prefix_size != hdr->GetSize() ||
                                !!memcmp(hdr->GetPointer() + prefix_size, nalUnit->GetDataPointer(), size);

                            if (isSPS && currSPS != nullptr)
                                currSPS->m_changed = changed;
                            else if (currPPS != nullptr)
                                currPPS->m_changed = changed;
                        }

                        hdr->Resize(id, size + prefix_size);
                        std::copy(start_code_prefix, start_code_prefix + prefix_size, hdr->GetPointer());
                        std::copy((uint8_t*)nalUnit->GetDataPointer(), (uint8_t*)nalUnit->GetDataPointer() + size, hdr->GetPointer() + prefix_size);
                    }
                }
            break;
        }
    }

    UMC::MediaDataEx::_MediaDataEx* pMediaDataEx = nalUnit->GetExData();
    if ((NalUnitType)pMediaDataEx->values[0] == NAL_UT_SPS && m_firstVideoParams.mfx.FrameInfo.Width)
    {
        H265SeqParamSet * currSPS = m_Headers.m_SeqParams.GetCurrentHeader();

        if (currSPS)
        {
            if (m_firstVideoParams.mfx.FrameInfo.Width < (currSPS->pic_width_in_luma_samples) ||
                m_firstVideoParams.mfx.FrameInfo.Height < (currSPS->pic_height_in_luma_samples) ||
                (currSPS->m_pcPTL.GetGeneralPTL()->level_idc && m_firstVideoParams.mfx.CodecLevel && m_firstVideoParams.mfx.CodecLevel < currSPS->m_pcPTL.GetGeneralPTL()->level_idc))
            {
                return UMC::UMC_NTF_NEW_RESOLUTION;
            }
        }

        return UMC::UMC_WRN_REPOSITION_INPROGRESS;
    }

    return UMC::UMC_OK;
}

// Decode SEI nal unit
UMC::Status MFXTaskSupplier_H265::DecodeSEI(UMC::MediaDataEx *nalUnit)
{
    if (m_Headers.m_SeqParams.GetCurrentID() == -1)
        return UMC::UMC_OK;

    H265HeadersBitstream bitStream;

    try
    {
        MemoryPiece mem;
        mem.SetData(nalUnit);

        MemoryPiece swappedMem;
        swappedMem.Allocate(nalUnit->GetDataSize() + DEFAULT_NU_TAIL_SIZE);

        SwapperBase * swapper = m_pNALSplitter->GetSwapper();
        swapper->SwapMemory(&swappedMem, &mem, 0);

        bitStream.Reset((uint8_t*)swappedMem.GetPointer(), (uint32_t)swappedMem.GetDataSize());

        NalUnitType nal_unit_type;
        uint32_t temporal_id;

        bitStream.GetNALUnitType(nal_unit_type, temporal_id);
        nalUnit->MoveDataPointer(2); // skip[ [NAL unit header = 16 bits]

        do
        {
            H265SEIPayLoad    m_SEIPayLoads;

            size_t decoded1 = bitStream.BytesDecoded();

            bitStream.ParseSEI(m_Headers.m_SeqParams, m_Headers.m_SeqParams.GetCurrentID(), &m_SEIPayLoads);

            if (m_SEIPayLoads.payLoadType == SEI_USER_DATA_REGISTERED_TYPE)
            {
                m_UserData = m_SEIPayLoads;
            }
            else
            {
                if (m_SEIPayLoads.payLoadType == SEI_RESERVED)
                    continue;

                m_Headers.m_SEIParams.AddHeader(&m_SEIPayLoads);
            }

            size_t decoded2 = bitStream.BytesDecoded();

            // calculate payload size
            size_t size = decoded2 - decoded1;

            VM_ASSERT(size == m_SEIPayLoads.payLoadSize + 2 + (m_SEIPayLoads.payLoadSize / 255) + (m_SEIPayLoads.payLoadType / 255));

            if (m_sei_messages)
            {
                UMC::MediaDataEx nalUnit1;

                size_t nal_u_size = size;
                for(uint8_t *ptr = (uint8_t*)nalUnit->GetDataPointer(); ptr < (uint8_t*)nalUnit->GetDataPointer() + nal_u_size; ptr++)
                    if (ptr[0]==0 && ptr[1]==0 && ptr[2]==3)
                        nal_u_size += 1;

                nalUnit1.SetBufferPointer((uint8_t*)nalUnit->GetDataPointer(), nal_u_size);
                nalUnit1.SetDataSize(nal_u_size);
                nalUnit1.SetExData(nalUnit->GetExData());

                double start, stop;
                nalUnit->GetTime(start, stop);
                nalUnit1.SetTime(start, stop);

                nalUnit->MoveDataPointer((int32_t)nal_u_size);

                SEI_Storer_H265::SEI_Message* msg =
                    m_sei_messages->AddMessage(&nalUnit1, m_SEIPayLoads.payLoadType);
                //frame is bound to SEI prefix payloads w/ the first slice
                //here we bind SEI suffix payloads
                if (msg && msg->nal_type == NAL_UT_SEI_SUFFIX)
                    msg->frame = GetView()->pCurFrame;
            }

        } while (bitStream.More_RBSP_Data());

    } catch(...)
    {
        // nothing to do just catch it
    }

    return UMC::UMC_OK;
}

// Do something in case reference frame is missing
void MFXTaskSupplier_H265::AddFakeReferenceFrame(H265Slice * )
{
}

} // namespace UMC_HEVC_DECODER

#endif // MFX_ENABLE_H265_VIDEO_DECODE
<commit_msg>[h265d/UMC]Fix saving SPS/PPS<commit_after>// Copyright (c) 2017-2018 Intel Corporation
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include "umc_defs.h"
#ifdef MFX_ENABLE_H265_VIDEO_DECODE

#include "umc_h265_mfx_supplier.h"

#include "umc_h265_frame_list.h"
#include "umc_h265_nal_spl.h"
#include "umc_h265_bitstream_headers.h"

#include "umc_h265_dec_defs.h"

#include "vm_sys_info.h"

#include "umc_h265_debug.h"

#include "umc_h265_mfx_utils.h"

namespace UMC_HEVC_DECODER
{

////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////
RawHeader_H265::RawHeader_H265()
{
    Reset();
}

void RawHeader_H265::Reset()
{
    m_id = -1;
    m_buffer.clear();
}

int32_t RawHeader_H265::GetID() const
{
    return m_id;
}

size_t RawHeader_H265::GetSize() const
{
    return m_buffer.size();
}

uint8_t * RawHeader_H265::GetPointer()
{
    return
        m_buffer.empty() ? nullptr : &m_buffer[0];
}

void RawHeader_H265::Resize(int32_t id, size_t newSize)
{
    m_id = id;
    m_buffer.resize(newSize);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////
void RawHeaders_H265::Reset()
{
    m_sps.Reset();
    m_pps.Reset();
}

RawHeader_H265 * RawHeaders_H265::GetSPS()
{
    return &m_sps;
}

RawHeader_H265 * RawHeaders_H265::GetPPS()
{
    return &m_pps;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////
MFXTaskSupplier_H265::MFXTaskSupplier_H265()
    : TaskSupplier_H265()
{
    memset(&m_firstVideoParams, 0, sizeof(mfxVideoParam));
}

MFXTaskSupplier_H265::~MFXTaskSupplier_H265()
{
    Close();
}

// Initialize task supplier
UMC::Status MFXTaskSupplier_H265::Init(UMC::VideoDecoderParams *init)
{
    UMC::Status umcRes;

    if (NULL == init)
        return UMC::UMC_ERR_NULL_PTR;

    Close();

    m_initializationParams = *init;
    m_pMemoryAllocator = init->lpMemoryAllocator;
    m_DPBSizeEx = 0;

    m_sei_messages = new SEI_Storer_H265();
    m_sei_messages->Init();

    int32_t nAllowedThreadNumber = init->numThreads;
    if(nAllowedThreadNumber < 0) nAllowedThreadNumber = 0;

    // calculate number of slice decoders.
    // It should be equal to CPU number
    m_iThreadNum = (0 == nAllowedThreadNumber) ? (vm_sys_info_get_cpu_num()) : (nAllowedThreadNumber);

    umcRes = MVC_Extension::Init();
    if (UMC::UMC_OK != umcRes)
    {
        return umcRes;
    }

    AU_Splitter_H265::Init(init);

    m_pSegmentDecoder = new H265SegmentDecoderBase *[m_iThreadNum];
    memset(m_pSegmentDecoder, 0, sizeof(H265SegmentDecoderBase *) * m_iThreadNum);

    CreateTaskBroker();
    m_pTaskBroker->Init(m_iThreadNum);

    for (uint32_t i = 0; i < m_iThreadNum; i += 1)
    {
        if (UMC::UMC_OK != m_pSegmentDecoder[i]->Init(i))
            return UMC::UMC_ERR_INIT;
    }

    m_local_delta_frame_time = 1.0/30;
    m_frameOrder             = 0;
    m_use_external_framerate = 0 < init->info.framerate;

    if (m_use_external_framerate)
    {
        m_local_delta_frame_time = 1 / init->info.framerate;
    }

    GetView()->dpbSize = 16;
    m_DPBSizeEx = m_iThreadNum + init->info.bitrate;

    return UMC::UMC_OK;
}

// Check whether specified frame has been decoded, and if it was,
// whether it is necessary to display some frame
bool MFXTaskSupplier_H265::CheckDecoding(bool should_additional_check, H265DecoderFrame * outputFrame)
{
    ViewItem_H265 &view = *GetView();

    if (!outputFrame->IsDecodingStarted())
        return false;

    if (outputFrame->IsDecodingCompleted())
    {
        if (!should_additional_check)
            return true;

        int32_t maxReadyUID = outputFrame->m_UID;
        uint32_t inDisplayStage = 0;

        UMC::AutomaticUMCMutex guard(m_mGuard);

        for (H265DecoderFrame * pTmp = view.pDPB->head(); pTmp; pTmp = pTmp->future())
        {
            if (pTmp->m_wasOutputted != 0 && pTmp->m_wasDisplayed == 0 && pTmp->m_maxUIDWhenWasDisplayed)
            {
                inDisplayStage++; // number of outputted frames at this moment
            }

            if ((pTmp->IsDecoded() || pTmp->IsDecodingCompleted()) && maxReadyUID < pTmp->m_UID)
                maxReadyUID = pTmp->m_UID;
        }

        DEBUG_PRINT1((VM_STRING("output frame - %d, notDecoded - %u, count - %u\n"), outputFrame->m_PicOrderCnt, notDecoded, count));
        if (inDisplayStage > 1 || m_maxUIDWhenWasDisplayed <= maxReadyUID)
        {
            return true;
        }
    }

    return false;
}

// Perform decoding task for thread number threadNumber
mfxStatus MFXTaskSupplier_H265::RunThread(mfxU32 threadNumber)
{
    UMC::Status sts = m_pSegmentDecoder[threadNumber]->ProcessSegment();

    if (sts == UMC::UMC_ERR_NOT_ENOUGH_DATA)
        return MFX_TASK_BUSY;
    else if(sts == UMC::UMC_ERR_DEVICE_FAILED)
        return MFX_ERR_DEVICE_FAILED;
    else if (sts == UMC::UMC_ERR_GPU_HANG)
        return MFX_ERR_GPU_HANG;

    if (sts != UMC::UMC_OK)
        return MFX_ERR_UNDEFINED_BEHAVIOR;

    return MFX_TASK_WORKING;
}

// Check whether all slices for the frame were found
void MFXTaskSupplier_H265::CompleteFrame(H265DecoderFrame * pFrame)
{
    if (!pFrame)
        return;

    H265DecoderFrameInfo * slicesInfo = pFrame->GetAU();
    if (slicesInfo->GetStatus() > H265DecoderFrameInfo::STATUS_NOT_FILLED)
        return;

    TaskSupplier_H265::CompleteFrame(pFrame);
}

// Set initial video params from application
void MFXTaskSupplier_H265::SetVideoParams(mfxVideoParam * par)
{
    m_firstVideoParams = *par;
    m_decodedOrder     = m_firstVideoParams.mfx.DecodedOrder != 0;
}

UMC::Status MFXTaskSupplier_H265::FillVideoParam(mfxVideoParam *par, bool full)
{
    const H265SeqParamSet * seq = GetHeaders()->m_SeqParams.GetCurrentHeader();
    if (!seq)
        return UMC::UMC_ERR_FAILED;

    if (MFX_Utility::FillVideoParam(seq, par, full) != UMC::UMC_OK)
        return UMC::UMC_ERR_FAILED;

    return UMC::UMC_OK;
}

// Decode headers nal unit
UMC::Status MFXTaskSupplier_H265::DecodeHeaders(UMC::MediaDataEx *nalUnit)
{
    UMC::Status sts = TaskSupplier_H265::DecodeHeaders(nalUnit);
    if (sts != UMC::UMC_OK)
        return sts;

    {
        // save sps/pps
        uint32_t nal_unit_type = nalUnit->GetExData()->values[0];
        switch(nal_unit_type)
        {
            case NAL_UT_SPS:
            case NAL_UT_PPS:
                {
                    static const uint8_t start_code_prefix[] = {0, 0, 0, 1};
                    size_t const prefix_size = sizeof(start_code_prefix);

                    size_t size = nalUnit->GetDataSize();
                    bool isSPS = (nal_unit_type == NAL_UT_SPS);
                    RawHeader_H265 * hdr = isSPS ? GetSPS() : GetPPS();
                    H265SeqParamSet * currSPS = isSPS ? m_Headers.m_SeqParams.GetCurrentHeader() : nullptr;
                    H265PicParamSet * currPPS = isSPS ? nullptr : m_Headers.m_PicParams.GetCurrentHeader();
                    int32_t id = isSPS ? m_Headers.m_SeqParams.GetCurrentID() : m_Headers.m_PicParams.GetCurrentID();
                    if (hdr->GetPointer() != nullptr && hdr->GetID() == id)
                    {
                        bool changed =
                            size + prefix_size != hdr->GetSize() ||
                            !!memcmp(hdr->GetPointer() + prefix_size, nalUnit->GetDataPointer(), size);

                        if (isSPS && currSPS != nullptr)
                            currSPS->m_changed = changed;
                        else if (currPPS != nullptr)
                            currPPS->m_changed = changed;
                    }
                    hdr->Resize(id, size + prefix_size);
                    std::copy(start_code_prefix, start_code_prefix + prefix_size, hdr->GetPointer());
                    std::copy((uint8_t*)nalUnit->GetDataPointer(), (uint8_t*)nalUnit->GetDataPointer() + size, hdr->GetPointer() + prefix_size);
                }
            break;
        }
    }

    UMC::MediaDataEx::_MediaDataEx* pMediaDataEx = nalUnit->GetExData();
    if ((NalUnitType)pMediaDataEx->values[0] == NAL_UT_SPS && m_firstVideoParams.mfx.FrameInfo.Width)
    {
        H265SeqParamSet * currSPS = m_Headers.m_SeqParams.GetCurrentHeader();

        if (currSPS)
        {
            if (m_firstVideoParams.mfx.FrameInfo.Width < (currSPS->pic_width_in_luma_samples) ||
                m_firstVideoParams.mfx.FrameInfo.Height < (currSPS->pic_height_in_luma_samples) ||
                (currSPS->m_pcPTL.GetGeneralPTL()->level_idc && m_firstVideoParams.mfx.CodecLevel && m_firstVideoParams.mfx.CodecLevel < currSPS->m_pcPTL.GetGeneralPTL()->level_idc))
            {
                return UMC::UMC_NTF_NEW_RESOLUTION;
            }
        }

        return UMC::UMC_WRN_REPOSITION_INPROGRESS;
    }

    return UMC::UMC_OK;
}

// Decode SEI nal unit
UMC::Status MFXTaskSupplier_H265::DecodeSEI(UMC::MediaDataEx *nalUnit)
{
    if (m_Headers.m_SeqParams.GetCurrentID() == -1)
        return UMC::UMC_OK;

    H265HeadersBitstream bitStream;

    try
    {
        MemoryPiece mem;
        mem.SetData(nalUnit);

        MemoryPiece swappedMem;
        swappedMem.Allocate(nalUnit->GetDataSize() + DEFAULT_NU_TAIL_SIZE);

        SwapperBase * swapper = m_pNALSplitter->GetSwapper();
        swapper->SwapMemory(&swappedMem, &mem, 0);

        bitStream.Reset((uint8_t*)swappedMem.GetPointer(), (uint32_t)swappedMem.GetDataSize());

        NalUnitType nal_unit_type;
        uint32_t temporal_id;

        bitStream.GetNALUnitType(nal_unit_type, temporal_id);
        nalUnit->MoveDataPointer(2); // skip[ [NAL unit header = 16 bits]

        do
        {
            H265SEIPayLoad    m_SEIPayLoads;

            size_t decoded1 = bitStream.BytesDecoded();

            bitStream.ParseSEI(m_Headers.m_SeqParams, m_Headers.m_SeqParams.GetCurrentID(), &m_SEIPayLoads);

            if (m_SEIPayLoads.payLoadType == SEI_USER_DATA_REGISTERED_TYPE)
            {
                m_UserData = m_SEIPayLoads;
            }
            else
            {
                if (m_SEIPayLoads.payLoadType == SEI_RESERVED)
                    continue;

                m_Headers.m_SEIParams.AddHeader(&m_SEIPayLoads);
            }

            size_t decoded2 = bitStream.BytesDecoded();

            // calculate payload size
            size_t size = decoded2 - decoded1;

            VM_ASSERT(size == m_SEIPayLoads.payLoadSize + 2 + (m_SEIPayLoads.payLoadSize / 255) + (m_SEIPayLoads.payLoadType / 255));

            if (m_sei_messages)
            {
                UMC::MediaDataEx nalUnit1;

                size_t nal_u_size = size;
                for(uint8_t *ptr = (uint8_t*)nalUnit->GetDataPointer(); ptr < (uint8_t*)nalUnit->GetDataPointer() + nal_u_size; ptr++)
                    if (ptr[0]==0 && ptr[1]==0 && ptr[2]==3)
                        nal_u_size += 1;

                nalUnit1.SetBufferPointer((uint8_t*)nalUnit->GetDataPointer(), nal_u_size);
                nalUnit1.SetDataSize(nal_u_size);
                nalUnit1.SetExData(nalUnit->GetExData());

                double start, stop;
                nalUnit->GetTime(start, stop);
                nalUnit1.SetTime(start, stop);

                nalUnit->MoveDataPointer((int32_t)nal_u_size);

                SEI_Storer_H265::SEI_Message* msg =
                    m_sei_messages->AddMessage(&nalUnit1, m_SEIPayLoads.payLoadType);
                //frame is bound to SEI prefix payloads w/ the first slice
                //here we bind SEI suffix payloads
                if (msg && msg->nal_type == NAL_UT_SEI_SUFFIX)
                    msg->frame = GetView()->pCurFrame;
            }

        } while (bitStream.More_RBSP_Data());

    } catch(...)
    {
        // nothing to do just catch it
    }

    return UMC::UMC_OK;
}

// Do something in case reference frame is missing
void MFXTaskSupplier_H265::AddFakeReferenceFrame(H265Slice * )
{
}

} // namespace UMC_HEVC_DECODER

#endif // MFX_ENABLE_H265_VIDEO_DECODE
<|endoftext|>


<commit_before>#include <algorithm>
#include <random>
#include <stack>
#include <vector>

#include "aim.hpp"
#include "maze.hpp"

struct Delta
{
  int x, y;
  Delta(int x, int y) : x(x), y(y) {}
};

struct UnvisitOnDelete
{
  char** maze_;
  Dimension dim_;
  UnvisitOnDelete(char** maze, Dimension const& dim) : maze_(maze), dim_(dim) {}
  ~UnvisitOnDelete()
  {
    const char visited { to_char(MazeElement::Undefined) };
    const char wall { to_char(MazeElement::Wall) };
    for (std::size_t j {} ; j < dim_.height ; j += 2)
    {
      for (std::size_t i {} ; i < dim_.width ; i += 2)
      {
        if (maze_[j][i] == visited) { maze_[j][i] = wall; }
      }
    }
  }
};

// Check properties

static bool is_inside(char** /*maze*/, Dimension const& dim, Point const& pt)
{
  return pt.x < dim.width && pt.y < dim.height;
}
static bool is_wall(char** maze, Dimension const& /*dim*/, Point const& pt)
{
  return maze[pt.y][pt.x] == to_char(MazeElement::Wall);
}
static bool is_inside_wall(char** maze, Dimension const& dim, Point const& pt)
{
  return is_inside(maze, dim, pt) && is_wall(maze, dim, pt);
}

static bool can_reach_end(char** maze, Dimension const& dim, Point const& origin, Point const& end)
{
  UnvisitOnDelete undoMe { maze, dim };

  std::stack<Point> can_be_visited;
  auto push_and_visit = [&can_be_visited,&maze,visited=to_char(MazeElement::Undefined)](auto&& pt) {
      can_be_visited.push(pt);
      maze[pt.y][pt.x] = visited;
  };

  push_and_visit(origin);
  while (! can_be_visited.empty())
  {
    Point pt { can_be_visited.top() };
    can_be_visited.pop();
    if (pt == end) { return true; }

    if (is_inside_wall(maze, dim, Point{pt.x-2, pt.y})) { push_and_visit(Point{pt.x-2, pt.y}); }
    if (is_inside_wall(maze, dim, Point{pt.x+2, pt.y})) { push_and_visit(Point{pt.x+2, pt.y}); }
    if (is_inside_wall(maze, dim, Point{pt.x, pt.y-2})) { push_and_visit(Point{pt.x, pt.y-2}); }
    if (is_inside_wall(maze, dim, Point{pt.x, pt.y+2})) { push_and_visit(Point{pt.x, pt.y+2}); }
  }
  return false;
}

// Helpers

template <class Container, class Predicate>
static void push_if(Container& container, char** maze, Dimension const& dim, Point const& pt, Delta const& delta, Predicate&& predicate)
{
  if (predicate(maze, dim, Point{pt.x + 2*delta.x, pt.y + 2*delta.y}))
  {
    container.push_back(delta);
  }
}

template <class Predicate, class Gen>
static auto build_choices(char** maze, Dimension const& dim, Point const& pt, Predicate&& predicate, Gen& g)
{
  std::vector<Delta> choices;
  push_if(choices, maze, dim, pt, Delta{-1, 0}, predicate);
  push_if(choices, maze, dim, pt, Delta{ 1, 0}, predicate);
  push_if(choices, maze, dim, pt, Delta{ 0,-1}, predicate);
  push_if(choices, maze, dim, pt, Delta{ 0, 1}, predicate);
  std::shuffle(choices.begin(), choices.end(), g);
  return choices;
}

template <class Gen>
static void adapt_for_traps(std::vector<std::pair<Point, std::vector<Delta>>>& main_roads, char** maze, Dimension const& dim, Gen& g)
{
  main_roads.erase(
      std::remove_if(main_roads.begin(), main_roads.end(), [](auto&& details) { return details.first.x % 2 != 0 || details.first.y % 2 != 0; })
      , main_roads.end());
  std::transform(main_roads.begin(), main_roads.end()
      , main_roads.begin()
      , [&](auto&& details) { return std::make_pair(details.first, build_choices(maze, dim, details.first, is_inside_wall, g)); });
  main_roads.erase(
      std::remove_if(main_roads.begin(), main_roads.end(), [](auto&& details) { return details.second.empty(); })
      , main_roads.end());
  std::shuffle(main_roads.begin(), main_roads.end(), g);
}

// Maze generation steps

static void reset(char** maze, Dimension const& dim)
{
  std::for_each(maze, maze+dim.height
	  , [width = dim.width, wall = to_char(MazeElement::Wall)](char* line) { std::fill(line, line + width, wall); });
}

template <class Gen>
static auto generate_main_path(char** maze, Dimension const& dim, Point const& start_pt, Point const& end_pt, Gen& g)
{
  // Generate a random path starting at start_pt and going to end_pt
  // Only one path will be generated

  const char road = to_char(MazeElement::Road);
  const char wall = to_char(MazeElement::Wall);

  auto path_to_end = std::vector<std::pair<Point, std::vector<Delta>>>{};
  auto current = Point{ start_pt };
  auto choices = build_choices(maze, dim, current, is_inside_wall, g);

  while (current != end_pt)
  {
    if (choices.empty())
    {// no more choices: backtrack
      current = path_to_end.back().first;
      maze[current.y][current.x] = wall;
      path_to_end.pop_back();

      current = path_to_end.back().first;
      choices = std::move(path_to_end.back().second);
      maze[current.y][current.x] = wall;
      path_to_end.pop_back();
      continue;
    }

    auto d  = Delta{ choices.back() };
    choices.pop_back();

    // check if such path can lead to the end of the maze
    maze[current.y][current.x] = road;
    if (! can_reach_end(maze, dim, Point{ current.x + 2 * d.x, current.y + 2 * d.y }, end_pt))
    {
      maze[current.y][current.x] = to_char(MazeElement::Wall);
      continue;
    }

    // current decision
    path_to_end.emplace_back(current, std::move(choices));

    // junction road
    current = Point{ current.x + d.x, current.y + d.y };
    path_to_end.emplace_back(current, decltype(choices){});
    maze[current.y][current.x] = road;

    // next position
    current = Point{ current.x + d.x, current.y + d.y };
    choices = build_choices(maze, dim, current, is_inside_wall, g);
  }

  maze[start_pt.y][start_pt.x] = to_char(MazeElement::Start);
  maze[end_pt.y][end_pt.x] = to_char(MazeElement::End);
  return path_to_end;
}

static void clean_not_accessible(char** maze, Dimension const& dim, std::pair<Point, std::vector<Delta>>& crossroad)
{
  auto const& pt = crossroad.first;
  auto& choices = crossroad.second;
  choices.erase(
      std::remove_if(choices.begin(), choices.end(), [&](auto const& d) { return ! is_inside_wall(maze, dim, Point{ pt.x + 2 * d.x, pt.y + 2 * d.y }); })
      , choices.end());
}

template <class Gen>
static void generate_trap_paths(char** maze, Dimension const& dim, std::vector<std::pair<Point, std::vector<Delta>>> nonfull_crossroads, Gen& g)
{
  const char road = to_char(MazeElement::Road);
  while (! nonfull_crossroads.empty())
  {
    auto const& pt { nonfull_crossroads.back().first };
    auto& choices { nonfull_crossroads.back().second };

    auto valid_delta = std::find_if(choices.begin(), choices.end()
		, [&](Delta d) { return is_inside_wall(maze, dim, Point{ pt.x + 2 * d.x, pt.y + 2 * d.y }); });

    if (valid_delta == choices.end())
    {// no path is accessible from this road
      // update possible choices of each road
      std::for_each(nonfull_crossroads.begin(), nonfull_crossroads.end(), [&](auto&& details) { clean_not_accessible(maze, dim, details); });
      // remove roads not having choices
      nonfull_crossroads.erase(
          std::remove_if(nonfull_crossroads.begin(), nonfull_crossroads.end(), [](auto&& details) { return details.second.empty(); })
          , nonfull_crossroads.end());
      // shuffle remaining roads
      std::shuffle(nonfull_crossroads.begin(), nonfull_crossroads.end(), g);
      continue;
    }

    auto d = *valid_delta;
    auto junction = Point{ pt.x + d.x, pt.y + d.y };
    auto target = Point{ pt.x + 2 * d.x, pt.y + 2 * d.y };
    maze[junction.y][junction.x] = road;
    maze[target.y][target.x] = road;

    auto next_choices = build_choices(maze, dim, target, is_inside_wall, g);
    if (! next_choices.empty())
    {
      nonfull_crossroads.emplace_back(target, std::move(next_choices));
    }
  }
}

// Algorithm to be tested

void generate_maze(char** maze, Dimension const& dim, Point const& start_pt, Point const& end_pt, unsigned seed)
{
  std::mt19937 g(seed);

  reset(maze, dim);
  auto main_roads = generate_main_path(maze, dim, start_pt, end_pt, g);
  adapt_for_traps(main_roads, maze, dim, g);
  generate_trap_paths(maze, dim, std::move(main_roads), g);
}
<commit_msg>[maze-generator-no-odd] Try to fix compile issues on older compilers<commit_after>#include <algorithm>
#include <random>
#include <stack>
#include <vector>

#include "aim.hpp"
#include "maze.hpp"

struct Delta
{
  int x, y;
  Delta(int x, int y) : x(x), y(y) {}
};

struct UnvisitOnDelete
{
  char** maze_;
  Dimension dim_;
  UnvisitOnDelete(char** maze, Dimension const& dim) : maze_(maze), dim_(dim) {}
  ~UnvisitOnDelete()
  {
    const char visited { to_char(MazeElement::Undefined) };
    const char wall { to_char(MazeElement::Wall) };
    for (std::size_t j {} ; j < dim_.height ; j += 2)
    {
      for (std::size_t i {} ; i < dim_.width ; i += 2)
      {
        if (maze_[j][i] == visited) { maze_[j][i] = wall; }
      }
    }
  }
};

// Check properties

static bool is_inside(char** /*maze*/, Dimension const& dim, Point const& pt)
{
  return pt.x < dim.width && pt.y < dim.height;
}
static bool is_wall(char** maze, Dimension const& /*dim*/, Point const& pt)
{
  return maze[pt.y][pt.x] == to_char(MazeElement::Wall);
}
static bool is_inside_wall(char** maze, Dimension const& dim, Point const& pt)
{
  return is_inside(maze, dim, pt) && is_wall(maze, dim, pt);
}

static bool can_reach_end(char** maze, Dimension const& dim, Point const& origin, Point const& end)
{
  UnvisitOnDelete undoMe { maze, dim };

  std::stack<Point> can_be_visited;
  auto push_and_visit = [&can_be_visited,&maze,visited=to_char(MazeElement::Undefined)](auto&& pt) {
      can_be_visited.push(pt);
      maze[pt.y][pt.x] = visited;
  };

  push_and_visit(origin);
  while (! can_be_visited.empty())
  {
    Point pt { can_be_visited.top() };
    can_be_visited.pop();
    if (pt == end) { return true; }

    if (is_inside_wall(maze, dim, Point{pt.x-2, pt.y})) { push_and_visit(Point{pt.x-2, pt.y}); }
    if (is_inside_wall(maze, dim, Point{pt.x+2, pt.y})) { push_and_visit(Point{pt.x+2, pt.y}); }
    if (is_inside_wall(maze, dim, Point{pt.x, pt.y-2})) { push_and_visit(Point{pt.x, pt.y-2}); }
    if (is_inside_wall(maze, dim, Point{pt.x, pt.y+2})) { push_and_visit(Point{pt.x, pt.y+2}); }
  }
  return false;
}

// Helpers

template <class Container, class Predicate>
static void push_if(Container& container, char** maze, Dimension const& dim, Point const& pt, Delta const& delta, Predicate&& predicate)
{
  if (predicate(maze, dim, Point{pt.x + 2*delta.x, pt.y + 2*delta.y}))
  {
    container.push_back(delta);
  }
}

template <class Predicate, class Gen>
static auto build_choices(char** maze, Dimension const& dim, Point const& pt, Predicate&& predicate, Gen& g)
{
  std::vector<Delta> choices;
  push_if(choices, maze, dim, pt, Delta{-1, 0}, predicate);
  push_if(choices, maze, dim, pt, Delta{ 1, 0}, predicate);
  push_if(choices, maze, dim, pt, Delta{ 0,-1}, predicate);
  push_if(choices, maze, dim, pt, Delta{ 0, 1}, predicate);
  std::shuffle(choices.begin(), choices.end(), g);
  return choices;
}

template <class Gen>
static void adapt_for_traps(std::vector<std::pair<Point, std::vector<Delta>>>& main_roads, char** maze, Dimension const& dim, Gen& g)
{
  main_roads.erase(
      std::remove_if(main_roads.begin(), main_roads.end(), [](auto&& details) { return details.first.x % 2 != 0 || details.first.y % 2 != 0; })
      , main_roads.end());
  std::transform(main_roads.begin(), main_roads.end()
      , main_roads.begin()
      , [&](auto&& details) { return std::make_pair(details.first, build_choices(maze, dim, details.first, is_inside_wall, g)); });
  main_roads.erase(
      std::remove_if(main_roads.begin(), main_roads.end(), [](auto&& details) { return details.second.empty(); })
      , main_roads.end());
  std::shuffle(main_roads.begin(), main_roads.end(), g);
}

// Maze generation steps

static void reset(char** maze, Dimension const& dim)
{
  std::for_each(maze, maze+dim.height
	  , [width = dim.width, wall = to_char(MazeElement::Wall)](char* line) { std::fill(line, line + width, wall); });
}

template <class Gen>
static auto generate_main_path(char** maze, Dimension const& dim, Point const& start_pt, Point const& end_pt, Gen& g)
{
  // Generate a random path starting at start_pt and going to end_pt
  // Only one path will be generated

  const char road = to_char(MazeElement::Road);
  const char wall = to_char(MazeElement::Wall);

  auto path_to_end = std::vector<std::pair<Point, std::vector<Delta>>>{};
  auto current = Point{ start_pt };
  auto choices = build_choices(maze, dim, current, is_inside_wall, g);

  while (current != end_pt)
  {
    if (choices.empty())
    {// no more choices: backtrack
      current = path_to_end.back().first;
      maze[current.y][current.x] = wall;
      path_to_end.pop_back();

      current = path_to_end.back().first;
      choices = std::move(path_to_end.back().second);
      maze[current.y][current.x] = wall;
      path_to_end.pop_back();
      continue;
    }

    auto d  = Delta{ choices.back() };
    choices.pop_back();

    // check if such path can lead to the end of the maze
    maze[current.y][current.x] = road;
    if (! can_reach_end(maze, dim, Point{ current.x + 2 * d.x, current.y + 2 * d.y }, end_pt))
    {
      maze[current.y][current.x] = to_char(MazeElement::Wall);
      continue;
    }

    // current decision
    path_to_end.emplace_back(current, std::move(choices));

    // junction road
    current = Point{ current.x + d.x, current.y + d.y };
    path_to_end.emplace_back(current, decltype(choices){});
    maze[current.y][current.x] = road;

    // next position
    current = Point{ current.x + d.x, current.y + d.y };
    choices = build_choices(maze, dim, current, is_inside_wall, g);
  }

  maze[start_pt.y][start_pt.x] = to_char(MazeElement::Start);
  maze[end_pt.y][end_pt.x] = to_char(MazeElement::End);
  return path_to_end;
}

static void clean_not_accessible(char** maze, Dimension const& dim, std::pair<Point, std::vector<Delta>>& crossroad)
{
  auto const& pt = crossroad.first;
  auto& choices = crossroad.second;
  choices.erase(
      std::remove_if(choices.begin(), choices.end(), [&](auto const& d) { return ! is_inside_wall(maze, dim, Point{ pt.x + 2 * d.x, pt.y + 2 * d.y }); })
      , choices.end());
}

template <class Gen>
static void generate_trap_paths(char** maze, Dimension const& dim, std::vector<std::pair<Point, std::vector<Delta>>> nonfull_crossroads, Gen& g)
{
  const char road = to_char(MazeElement::Road);
  while (! nonfull_crossroads.empty())
  {
    auto const& pt = nonfull_crossroads.back().first;
    auto& choices = nonfull_crossroads.back().second;

    auto valid_delta = std::find_if(choices.begin(), choices.end()
		, [&](Delta d) { return is_inside_wall(maze, dim, Point{ pt.x + 2 * d.x, pt.y + 2 * d.y }); });

    if (valid_delta == choices.end())
    {// no path is accessible from this road
      // update possible choices of each road
      std::for_each(nonfull_crossroads.begin(), nonfull_crossroads.end(), [&](auto&& details) { clean_not_accessible(maze, dim, details); });
      // remove roads not having choices
      nonfull_crossroads.erase(
          std::remove_if(nonfull_crossroads.begin(), nonfull_crossroads.end(), [](auto&& details) { return details.second.empty(); })
          , nonfull_crossroads.end());
      // shuffle remaining roads
      std::shuffle(nonfull_crossroads.begin(), nonfull_crossroads.end(), g);
      continue;
    }

    auto d = *valid_delta;
    auto junction = Point{ pt.x + d.x, pt.y + d.y };
    auto target = Point{ pt.x + 2 * d.x, pt.y + 2 * d.y };
    maze[junction.y][junction.x] = road;
    maze[target.y][target.x] = road;

    auto next_choices = build_choices(maze, dim, target, is_inside_wall, g);
    if (! next_choices.empty())
    {
      nonfull_crossroads.emplace_back(target, std::move(next_choices));
    }
  }
}

// Algorithm to be tested

void generate_maze(char** maze, Dimension const& dim, Point const& start_pt, Point const& end_pt, unsigned seed)
{
  std::mt19937 g(seed);

  reset(maze, dim);
  auto main_roads = generate_main_path(maze, dim, start_pt, end_pt, g);
  adapt_for_traps(main_roads, maze, dim, g);
  generate_trap_paths(maze, dim, std::move(main_roads), g);
}
<|endoftext|>


<commit_before>#include "queue thread safe.hpp"
#include "gtest/gtest.h"
#include <thread>
#include <algorithm>
#include "aux_tests.hpp"

TEST(Push,HandleBasicOperation){
	std::threadsafe::queue<int> queue;

	int out;
	for (int i = 1;i <= 10;i++){
			queue.push(i);

			queue.wait_back(out);
			EXPECT_EQ(i,out);

			queue.wait_top(out);
			EXPECT_EQ(out,1);
			EXPECT_EQ(i,queue.size());
	}

	for (int i = 1;i <= 10;i++){
			queue.wait_pop(out);
			EXPECT_EQ(i,out);
			EXPECT_EQ(10-i,queue.size());
	}
}

TEST(Push,ThreadSafety){

	std::threadsafe::queue<int> queue;
	std::threadsafe::queue<int> another_queue;
	constexpr int ITERATIONS = 10;
	constexpr int PRODUCERS = ITERATIONS;
	constexpr int CONSUMERS = ITERATIONS;

	auto producer = [&](int id,int it){queue.push(id);};
	auto consumer = [&](int id,int it){
					int out;
					queue.wait_pop(out);
					ASSERT_LT(out,ITERATIONS);
					ASSERT_GE(out,0);
					another_queue.push(out);
					};

	launchThreads(producer,consumer,PRODUCERS,CONSUMERS,ITERATIONS);

	ASSERT_EQ(ITERATIONS*ITERATIONS,another_queue.size());

	int freq_table[ITERATIONS];
	std::fill(freq_table,freq_table+ITERATIONS,0);
	while (!another_queue.empty()){
		int out;
		another_queue.wait_pop(out);
		freq_table[out]++;
	}

	for (int i = 0;i < ITERATIONS;i++)
	{
		ASSERT_EQ(ITERATIONS,freq_table[i]);
	}
}
<commit_msg>Added test upper bound in queue<commit_after>#include "queue thread safe.hpp"
#include "gtest/gtest.h"
#include <thread>
#include <algorithm>
#include "aux_tests.hpp"

TEST(Push,HandleBasicOperation){
	std::threadsafe::queue<int> queue;

	int out;
	for (int i = 1;i <= 10;i++){
			queue.push(i);

			queue.wait_back(out);
			EXPECT_EQ(i,out);

			queue.wait_top(out);
			EXPECT_EQ(out,1);
			EXPECT_EQ(i,queue.size());
	}

	for (int i = 1;i <= 10;i++){
			queue.wait_pop(out);
			EXPECT_EQ(i,out);
			EXPECT_EQ(10-i,queue.size());
	}
}

TEST(Push,ThreadSafety){

	std::threadsafe::queue<int> queue;
	std::threadsafe::queue<int> another_queue;
	constexpr int ITERATIONS = 10;
	constexpr int PRODUCERS = ITERATIONS;
	constexpr int CONSUMERS = ITERATIONS;

	auto producer = [&](int id,int it){queue.push(id);};
	auto consumer = [&](int id,int it){
					int out;
					queue.wait_pop(out);
					ASSERT_LT(out,ITERATIONS);
					ASSERT_GE(out,0);
					another_queue.push(out);
					};

	launchThreads(producer,consumer,PRODUCERS,CONSUMERS,ITERATIONS);

	ASSERT_EQ(ITERATIONS*ITERATIONS,another_queue.size());

	int freq_table[ITERATIONS];
	std::fill(freq_table,freq_table+ITERATIONS,0);
	while (!another_queue.empty()){
		int out;
		another_queue.wait_pop(out);
		freq_table[out]++;
	}

	for (int i = 0;i < ITERATIONS;i++)
	{
		ASSERT_EQ(ITERATIONS,freq_table[i]);
	}
}

TEST(Push,UpperBound){
	std::threadsafe::queue<int> queue;
	constexpr int ITERATIONS_PRODUCERS = 10;
	constexpr int NUM_PRODUCERS = ITERATIONS_PRODUCERS;
	constexpr int NUM_CONSUMERS = 1;
	constexpr int SIZE = NUM_PRODUCERS/2;
	constexpr int ITERATIONS_CONSUMERS = ITERATIONS_PRODUCERS*NUM_PRODUCERS;
	queue.setLimit(SIZE);

	auto producer = [&](int id,int it){
				queue.push(id);
				ASSERT_LE(queue.size(),SIZE);
			};
	auto consumer = [&](int id,int it){
				int out;
				ASSERT_LE(queue.size(),SIZE);
				queue.wait_pop(out);
			};

	launchThreads(producer,consumer,NUM_PRODUCERS,NUM_CONSUMERS,ITERATIONS_PRODUCERS,ITERATIONS_CONSUMERS);
}
<|endoftext|>


<commit_before>#include "Controller.h"

namespace ADBLib
{
	ctrlCfg::ctrlCfg()
	{
		id = 0;
		type = JOYSTICK;
		inverse = false;
		btn.toggle = false;
		btn.cooldown = 0.250; //Seconds
		btn.cooldownTimer = new Timer;
		jys.maxVal = 1.0;
		jys.minVal = -1.0;
		jys.deadzone = 0.1;
		jys.equ.parse("x"); //Start off with no alterations to the joystick equation
	}

	Controller::~Controller()
	{
		delete joystick;
	}

	ctrlCfg::btnCfg::~btnCfg()
	{
		delete cooldownTimer;
	}

	/**
	 * @brief Gets the raw button setting as true or false, disregarding any active cooldowns.
	 * @param ID The ID of the button. ID changes depending on controller mode (X-Mode or D-Mode)
	 */
	bool Controller::getButtonRaw(int ID)
	{
		if ((ID >= 15 || ID <= 0) && joystick != nullptr)
			return false; //Out-of-bounds IDs not accepted.
		return joystick->GetRawButton(ID);
	}

	/**
	 * @brief Gets the raw axis value.
	 * @param ID The ID of the joystick. ID changes depending on controller mode (X-Mode or D-Mode)
	 */
	double Controller::getJoystickRaw(int ID)
	{
		if (ID >= 0 && ID <= 15 && joystick != nullptr)
			return joystick->GetRawAxis(ID);
		else
			return 0;
	}

	/**
	 * @brief Sets the joystick to get data from.
	 * @param newJoystick A shared pointer to the joystick to use.
	 */
	void Controller::setJoystick(Joystick* newJoystick)
	{
		joystick = newJoystick;
	}

	/**
	 * @brief Make the controller rumble using built-in rumbler thingies.
	 * @param side The side on which the joystick will rumble. Definedby WPILib.
	 * @param intensity The intensity of vibration on a scale from 0 to 1.
	 */
	void Controller::setRumble(Joystick::RumbleType side, float intensity)
	{
		if (joystick != nullptr)
		joystick->SetRumble(side, intensity);
	}

	/**
	 * @brief Loads control settings from a config file, because hard-coded controls are awful.
	 *
	 *	Config files should be structured as follows:
	 *	* The root node should be called "ControlConfig".
	 *	* The children underneath the root node should be called "profile" with an attribute "name".
	 *	  This name is the name for a specific control profile. There should also be an attribute "active",
	 *	  which should be either true or false. This sets which control profile is active.
	 *	* Nodes underneath a profile node should be named "control". They should have an attribute "type"
	 *	  (either button or joystick), an attribute "name", which is how you will refer to the control in
	 *	  the code, and an "id" attribute, for the control ID.
	 *	* A control node's children should vary depending on control type.
	 *	  	* All children will name the type of parameter, whereas an XML attribute ("value") specifies the
	 *	  	  value.
	 *	  	* Button controls need only have "toggle" (boolean) and "cooldown" (double) parameters..
	 *	  	* Joystick controls have four parameters: maxInput, minInput, deadzone, and equation (how the resulting value is modified; negative-blind).
	 *	  	* Both button and joystick controls can accept an "inverse" (boolean) parameter, to invert output.
	 *
	 * An example (tiny) XML config file follows (you might need to check the source code, doxygen screws up the tabs!):
	 *
	 * <ControlConfig>
	 *	  <profile name="Sourec" active="false">
	 *		<control type="button" id="0" name="raiseForks">
	 *		  <toggle value="false"/>
	 *		  <cooldown value="0.250"/>
	 *		</control>
	 *		<control type="joystick" name="intakeWheels">
	 *		  <maxInput value="1.0"/>
	 *		  <minInput value="-1.0"/>
	 *	  	  <deadzone value="0.1"/>
	 *		  <equation value="x"/>
	 *		</control>
	 *	  </profile>
	 *	 </ControlConfig>
	 *
	 * @param cfgFile The path/filename to the config file.
	 * @note RoboRIOs are LINUX BASED! This means that your directory (even if it's just the root directory!) should start out with a '/' !
	 * @note NOT SETTING A CONTROL PARAMETER IN THE FILE WILL CAUSE DEFAULT VALUES TO BE USED! IF YOU SUSPECT ERROR, CHECK THE LOG!
	 */
	void Controller::parseConfig(string filename)
	{
		pugi::xml_document doc;
		pugi::xml_parse_result result = doc.load(filename.c_str());
		Hydra::Logger::log(result.description(), "sysLog", Hydra::hydsys);

		for (auto profile = doc.child("ControlConfig").child("profile"); profile; profile = profile.next_sibling())
		{ //Loop through all profiles
			unordered_map<string, ctrlCfg> profileSet;

			for (auto control = profile.child("control"); control; control = control.next_sibling())
			{ //Loop through all controls
				ctrlCfg newCtrl;
				newCtrl.id = control.attribute("id").as_int();
				if (control.attribute("type").as_string() == string("button"))
				{
					newCtrl.type = ctrlCfg::BUTTON;
					newCtrl.inverse = control.child("inverse").attribute("value").as_bool();
					newCtrl.btn.cooldown = control.child("cooldown").attribute("cooldown").as_double();
					newCtrl.btn.toggle = control.child("toggle").attribute("value").as_bool();
				}
				else
				{
					newCtrl.type = ctrlCfg::JOYSTICK;
					newCtrl.jys.maxVal = control.child("maxInput").attribute("value").as_double();
					newCtrl.jys.minVal = control.child("minInput").attribute("value").as_double();
					newCtrl.jys.deadzone = control.child("deadzone").attribute("value").as_double();
					newCtrl.jys.equ.parse(control.child("equation").attribute("value").as_string());
				}
				//profileSet[control.attribute("name").as_string()] = newCtrl;
			}
			profiles[profile.attribute("name").as_string()] = profileSet;

			if (profile.attribute("active").as_bool()) //Automatically switch to default active profiles
				switchProfile(profile.attribute("name").as_string());
		}
	}

	/**
	 * @brief Switches out the current control profile for another profile, specified by name.
	 * @param profileName The name of the profile to switch to as a string.
	 */
	void Controller::switchProfile(string profileName)
	{
		if (profiles.count(profileName) != 0)
			currentProfile = profileName;
	}

	/**
	 * @brief Get the value of a set control, referenced by name
	 * @param name The name of the control. Referenced in the XML configuration file.
	 * @return If the control is a button, nonzero for true and zero for false (duh). Else, a double.
	 */
	double Controller::operator[](const string& name)
	{
		ctrlCfg control;// = profiles[currentProfile][name]; //NOT a 2D array!
		if (control.type == ctrlCfg::BUTTON)
		{
			if (!control.btn.toggle)
				return control.inverse ? !joystick->GetRawButton(control.id) : joystick->GetRawButton(control.id);
			else if (joystick->GetRawButton(control.id) || (!joystick->GetRawButton(control.id) && control.inverse))
			{
				if (control.btn.cooldownTimer->Get() >= control.btn.cooldown)
				{ //The cooldown expired
					control.btn.cooldownTimer->Reset();
					control.btn.cooldownTimer->Start();
					return !control.inverse;
				}
				return control.inverse;
			}
		}
		else
		{ //It's a joystick
			double value = joystick->GetRawAxis(control.id);
			double temp = value;
			value = control.jys.equ.evaluate(fabs(value));
			value = std::copysign(temp, value); //Copysign from temp to value?

			//scale values... should work
			temp = value;
			value = fabs(value) * ((control.jys.maxVal - control.jys.minVal) * 0.5f);
			return std::copysign(temp, value) + control.jys.minVal; //TODO: Verify

		}
		return 0; //STOP YELLING AT ME, ECLIPSE
	}
}
<commit_msg>Potentially fixed controller class crash<commit_after>#include "Controller.h"

namespace ADBLib
{
	ctrlCfg::ctrlCfg()
	{
		id = 0;
		type = JOYSTICK;
		inverse = false;
		btn.toggle = false;
		btn.cooldown = 0.250; //Seconds
		btn.cooldownTimer = new Timer;
		jys.maxVal = 1.0;
		jys.minVal = -1.0;
		jys.deadzone = 0.1;
		jys.equ.parse("x"); //Start off with no alterations to the joystick equation
	}

	Controller::~Controller()
	{
		delete joystick;
	}

	ctrlCfg::btnCfg::~btnCfg()
	{
		delete cooldownTimer;
	}

	/**
	 * @brief Gets the raw button setting as true or false, disregarding any active cooldowns.
	 * @param ID The ID of the button. ID changes depending on controller mode (X-Mode or D-Mode)
	 */
	bool Controller::getButtonRaw(int ID)
	{
		if ((ID >= 15 || ID <= 0) && joystick != nullptr)
			return false; //Out-of-bounds IDs not accepted.
		return joystick->GetRawButton(ID);
	}

	/**
	 * @brief Gets the raw axis value.
	 * @param ID The ID of the joystick. ID changes depending on controller mode (X-Mode or D-Mode)
	 */
	double Controller::getJoystickRaw(int ID)
	{
		if (ID >= 0 && ID <= 15 && joystick != nullptr)
			return joystick->GetRawAxis(ID);
		else
			return 0;
	}

	/**
	 * @brief Sets the joystick to get data from.
	 * @param newJoystick A shared pointer to the joystick to use.
	 */
	void Controller::setJoystick(Joystick* newJoystick)
	{
		joystick = newJoystick;
	}

	/**
	 * @brief Make the controller rumble using built-in rumbler thingies.
	 * @param side The side on which the joystick will rumble. Definedby WPILib.
	 * @param intensity The intensity of vibration on a scale from 0 to 1.
	 */
	void Controller::setRumble(Joystick::RumbleType side, float intensity)
	{
		if (joystick != nullptr)
		joystick->SetRumble(side, intensity);
	}

	/**
	 * @brief Loads control settings from a config file, because hard-coded controls are awful.
	 *
	 *	Config files should be structured as follows:
	 *	* The root node should be called "ControlConfig".
	 *	* The children underneath the root node should be called "profile" with an attribute "name".
	 *	  This name is the name for a specific control profile. There should also be an attribute "active",
	 *	  which should be either true or false. This sets which control profile is active.
	 *	* Nodes underneath a profile node should be named "control". They should have an attribute "type"
	 *	  (either button or joystick), an attribute "name", which is how you will refer to the control in
	 *	  the code, and an "id" attribute, for the control ID.
	 *	* A control node's children should vary depending on control type.
	 *	  	* All children will name the type of parameter, whereas an XML attribute ("value") specifies the
	 *	  	  value.
	 *	  	* Button controls need only have "toggle" (boolean) and "cooldown" (double) parameters..
	 *	  	* Joystick controls have four parameters: maxInput, minInput, deadzone, and equation (how the resulting value is modified; negative-blind).
	 *	  	* Both button and joystick controls can accept an "inverse" (boolean) parameter, to invert output.
	 *
	 * An example (tiny) XML config file follows (you might need to check the source code, doxygen screws up the tabs!):
	 *
	 * <ControlConfig>
	 *	  <profile name="Sourec" active="false">
	 *		<control type="button" id="0" name="raiseForks">
	 *		  <toggle value="false"/>
	 *		  <cooldown value="0.250"/>
	 *		</control>
	 *		<control type="joystick" name="intakeWheels">
	 *		  <maxInput value="1.0"/>
	 *		  <minInput value="-1.0"/>
	 *	  	  <deadzone value="0.1"/>
	 *		  <equation value="x"/>
	 *		</control>
	 *	  </profile>
	 *	 </ControlConfig>
	 *
	 * @param cfgFile The path/filename to the config file.
	 * @note RoboRIOs are LINUX BASED! This means that your directory (even if it's just the root directory!) should start out with a '/' !
	 * @note NOT SETTING A CONTROL PARAMETER IN THE FILE WILL CAUSE DEFAULT VALUES TO BE USED! IF YOU SUSPECT ERROR, CHECK THE LOG!
	 */
	void Controller::parseConfig(string filename)
	{
		pugi::xml_document doc;
		pugi::xml_parse_result result = doc.load(filename.c_str());
		Hydra::Logger::log(result.description(), "sysLog", Hydra::hydsys);

		for (auto profile = doc.child("ControlConfig").child("profile"); profile; profile = profile.next_sibling())
		{ //Loop through all profiles
			unordered_map<string, ctrlCfg> profileSet;

			for (auto control = profile.child("control"); control; control = control.next_sibling())
			{ //Loop through all controls
				ctrlCfg newCtrl;
				newCtrl.id = control.attribute("id").as_int();
				if (control.attribute("type").as_string() == string("button"))
				{
					newCtrl.type = ctrlCfg::BUTTON;
					newCtrl.inverse = control.child("inverse").attribute("value").as_bool();
					newCtrl.btn.cooldown = control.child("cooldown").attribute("cooldown").as_double();
					newCtrl.btn.toggle = control.child("toggle").attribute("value").as_bool();
				}
				else
				{
					newCtrl.type = ctrlCfg::JOYSTICK;
					newCtrl.jys.maxVal = control.child("maxInput").attribute("value").as_double();
					newCtrl.jys.minVal = control.child("minInput").attribute("value").as_double();
					newCtrl.jys.deadzone = control.child("deadzone").attribute("value").as_double();
					newCtrl.jys.equ.parse(control.child("equation").attribute("value").as_string());
				}
				//profileSet[control.attribute("name").as_string()] = newCtrl;
			}
			profiles[profile.attribute("name").as_string()] = profileSet;

			if (profile.attribute("active").as_bool()) //Automatically switch to default active profiles
				switchProfile(profile.attribute("name").as_string());
		}
	}

	/**
	 * @brief Switches out the current control profile for another profile, specified by name.
	 * @param profileName The name of the profile to switch to as a string.
	 */
	void Controller::switchProfile(string profileName)
	{
		if (profiles.count(profileName) != 0)
			currentProfile = profileName;
	}

	/**
	 * @brief Get the value of a set control, referenced by name
	 * @param name The name of the control. Referenced in the XML configuration file.
	 * @return If the control is a button, nonzero for true and zero for false (duh). Else, a double.
	 */
	double Controller::operator[](const string& name)
	{
		if (profiles[currentProfile].count(name) == 0)
			return 0; //There IS no control by this name!

		ctrlCfg control = profiles[currentProfile][name];
		if (control.type == ctrlCfg::BUTTON)
		{
			if (!control.btn.toggle)
				return control.inverse ? !joystick->GetRawButton(control.id) : joystick->GetRawButton(control.id);
			else if (joystick->GetRawButton(control.id) || (!joystick->GetRawButton(control.id) && control.inverse))
			{
				if (control.btn.cooldownTimer->Get() >= control.btn.cooldown)
				{ //The cooldown expired
					control.btn.cooldownTimer->Reset();
					control.btn.cooldownTimer->Start();
					return !control.inverse;
				}
				return control.inverse;
			}
		}
		else
		{ //It's a joystick
			double value = joystick->GetRawAxis(control.id);
			double temp = value;
			value = control.jys.equ.evaluate(fabs(value));
			value = std::copysign(temp, value); //Copysign from temp to value?

			//scale values... should work
			temp = value;
			value = fabs(value) * ((control.jys.maxVal - control.jys.minVal) * 0.5f);
			return std::copysign(temp, value) + control.jys.minVal; //TODO: Verify

		}
		return 0; //STOP YELLING AT ME, ECLIPSE
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007 Digital Bazaar, Inc.  All rights reserved.
 */
#include "AbstractSocket.h"
#include "SocketDefinitions.h"
#include "InterruptedException.h"
#include "PeekInputStream.h"
#include "SocketInputStream.h"
#include "SocketOutputStream.h"
#include "Thread.h"

using namespace db::io;
using namespace db::net;
using namespace db::rt;

AbstractSocket::AbstractSocket()
{
   // file descriptor is invalid at this point
   mFileDescriptor = -1;

   // not bound, listening, or connected
   mBound = false;
   mListening = false;
   mConnected = false;

   // input/output uninitialized
   mInputStream = NULL;
   mOutputStream = NULL;

   // no receive or send timeouts (socket will block)
   mReceiveTimeout = 0;
   mSendTimeout = 0;

   // default backlog is 50
   mBacklog = 50;
}

AbstractSocket::~AbstractSocket()
{
   // close socket
   close();
}

bool AbstractSocket::create(int domain, int type, int protocol)
{
   bool rval = false;

   int fd = socket(domain, type, protocol);
   if(fd >= 0)
   {
      // set reuse address flag
      // disables "address already in use" errors by reclaiming ports that
      // are waiting to be cleaned up
      int reuse = 1;
      int error = setsockopt(
         fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse));
      if(error < 0)
      {
         // close socket
         close();

         Thread::setException(new SocketException(
            "Could not create Socket!", strerror(errno)));
      }
      else
      {
         mFileDescriptor = fd;
         rval = true;
      }
   }
   else
   {
      Thread::setException(new SocketException(
         "Could not create Socket!", strerror(errno)));
   }

   return rval;
}

bool AbstractSocket::select(bool read, long long timeout)
{
   Exception* exception = NULL;

   if(!Thread::interrupted(false))
   {
      // create a file descriptor set to select on
      fd_set fds;
      FD_ZERO(&fds);

      // add file descriptor to set
      FD_SET((unsigned int)mFileDescriptor, &fds);

      // "n" parameter is the highest numbered descriptor plus 1
      int n = mFileDescriptor + 1;

      int error;
      if(read)
      {
         // wait for data to arrive for reading or for an exception
         error = Thread::select(n, &fds, NULL, &fds, timeout);
      }
      else
      {
         // wait for writability or for an exception
         error = Thread::select(n, NULL, &fds, &fds, timeout);
      }

      if(error < 0)
      {
         if(errno == EINTR)
         {
            if(read)
            {
               // interrupted exception
               exception = new InterruptedException(
                  "Socket read interrupted!", strerror(errno));
            }
            else
            {
               // interrupted exception
               exception = new InterruptedException(
                  "Socket write interrupted!", strerror(errno));
            }
         }

         if(read)
         {
            // error occurred, get string message
            exception = new SocketException(
               "Could not read from Socket!", strerror(errno));
         }
         else
         {
            // error occurred, get string message
            exception = new SocketException(
               "Could not write to Socket!", strerror(errno));
         }
      }
      else if(error == 0)
      {
         if(read)
         {
            // read timeout occurred
            exception = new SocketTimeoutException(
               "Socket read timed out!", strerror(errno));
         }
         else
         {
            // write timeout occurred
            exception = new SocketTimeoutException(
               "Socket write timed out!", strerror(errno));
         }
      }
   }

   if(exception == NULL && Thread::interrupted(false))
   {
      if(read)
      {
         exception = new InterruptedException("Socket read interrupted!");
      }
      else
      {
         exception = new InterruptedException("Socket write interrupted!");
      }
   }

   if(exception != NULL)
   {
      Thread::setException(exception);
   }

   return exception == NULL;
}

bool AbstractSocket::initializeInput()
{
   if(mInputStream == NULL)
   {
      // create input stream
      mInputStream = new PeekInputStream(new SocketInputStream(this), true);
   }

   return true;
}

bool AbstractSocket::initializeOutput()
{
   if(mOutputStream == NULL)
   {
      // create output stream
      mOutputStream = new SocketOutputStream(this);
   }

   return true;
}

bool AbstractSocket::shutdownInput()
{
   // delete input stream
   if(mInputStream == NULL)
   {
      delete mInputStream;
   }

   return true;
}

bool AbstractSocket::shutdownOutput()
{
   // delete output stream
   if(mOutputStream == NULL)
   {
      delete mOutputStream;
   }

   return true;
}

bool AbstractSocket::bind(SocketAddress* address)
{
   // acquire file descriptor
   if(acquireFileDescriptor(address->getProtocol()))
   {
      // populate address structure
      unsigned int size = 130;
      char addr[size];
      address->toSockAddr((sockaddr*)&addr, size);

      // bind
      int error = ::bind(mFileDescriptor, (sockaddr*)&addr, size);
      if(error < 0)
      {
         Thread::setException(new SocketException(
            "Could not bind Socket!", strerror(errno)));
      }
      else
      {
         // initialize input and output
         initializeInput();
         initializeOutput();

         // now bound
         mBound = true;
      }
   }

   return mBound;
}

bool AbstractSocket::listen(unsigned int backlog)
{
   if(!isBound())
   {
      Thread::setException(new SocketException(
         "Cannot listen on unbound Socket!"));
   }
   else
   {
      // set backlog
      mBacklog = backlog;

      // listen
      int error = ::listen(mFileDescriptor, backlog);
      if(error < 0)
      {
         Thread::setException(new SocketException(
            "Could not listen on Socket!", strerror(errno)));
      }
      else
      {
         // now listening
         mListening = true;
      }
   }

   return mListening;
}

Socket* AbstractSocket::accept(unsigned int timeout)
{
   Socket* rval = NULL;

   if(!isListening())
   {
      Thread::setException(new SocketException(
         "Cannot accept with a non-listening Socket!"));
   }
   else
   {
      // wait for a connection
      if(select(true, timeout * 1000LL))
      {
         // accept a connection
         int fd = ::accept(mFileDescriptor, NULL, NULL);
         if(fd < 0)
         {
            Thread::setException(new SocketException(
               "Could not accept connection!", strerror(errno)));
         }
         else
         {
            // create a connected Socket
            rval = createConnectedSocket(fd);
         }
      }
   }

   return rval;
}

bool AbstractSocket::connect(SocketAddress* address, unsigned int timeout)
{
   // acquire file descriptor
   if(acquireFileDescriptor(address->getProtocol()))
   {
      // populate address structure
      unsigned int size = 130;
      char addr[size];
      address->toSockAddr((sockaddr*)&addr, size);

      // make socket non-blocking temporarily
      fcntl(mFileDescriptor, F_SETFL, O_NONBLOCK);

      // connect
      int error = ::connect(mFileDescriptor, (sockaddr*)addr, size);
      if(error < 0)
      {
         // wait until the connection can be written to
         if(select(false, timeout * 1000LL))
         {
            // get the last error on the socket
            int lastError;
            socklen_t lastErrorLength = sizeof(lastError);
            getsockopt(
               mFileDescriptor, SOL_SOCKET, SO_ERROR,
               (char*)&lastError, &lastErrorLength);
            if(lastError == 0)
            {
               // now connected and bound
               mBound = true;
               mConnected = true;
            }
            else
            {
               Thread::setException(new SocketException(
                  "Could not connect Socket! Connection refused.",
                  strerror(lastError)));
            }
         }
      }
      else
      {
         // now connected and bound
         mBound = true;
         mConnected = true;
      }

      // restore socket to blocking
      fcntl(mFileDescriptor, F_SETFL, 0);

      if(mConnected)
      {
         // initialize input and output
         initializeInput();
         initializeOutput();
      }
   }

   return mConnected;
}

bool AbstractSocket::send(const char* b, unsigned int length)
{
   Exception* exception = NULL;

   if(!isBound())
   {
      exception = new SocketException("Cannot write to unbound Socket!");
   }
   else
   {
      // send all data (send can fail to send all bytes in one go because the
      // socket send buffer was full)
      unsigned int offset = 0;
      while(exception == NULL && length > 0)
      {
         // wait for socket to become writable
         if(select(false, getSendTimeout()))
         {
            // send some data
            int bytes = ::send(mFileDescriptor, b + offset, length, 0);
            if(bytes < 0)
            {
               exception = new SocketException(
                  "Could not write to Socket!", strerror(errno));
            }
            else if(bytes > 0)
            {
               offset += bytes;
               length -= bytes;
            }
         }
         else
         {
            exception = Thread::getException();
         }
      }
   }

   if(exception != NULL)
   {
      Thread::setException(exception);
   }

   return exception == NULL;
}

int AbstractSocket::receive(char* b, unsigned int length)
{
   int rval = -1;

   if(!isBound())
   {
      Thread::setException(new SocketException(
         "Cannot read from unbound Socket!"));
   }
   else
   {
      // wait for data to become available
      if(select(true, getReceiveTimeout()))
      {
         // receive some data
         rval = ::recv(mFileDescriptor, b, length, 0);
         if(rval < -1)
         {
            rval = -1;
            Thread::setException(new SocketException(
               "Could not read from Socket!", strerror(errno)));
         }
         else if(rval == 0)
         {
            // socket is closed now
            rval = -1;
         }
      }
   }

   return rval;
}

void AbstractSocket::close()
{
   if(mFileDescriptor != -1)
   {
      // shutdown input and output
      shutdownInput();
      shutdownOutput();

      // close the socket
      ::close(mFileDescriptor);

      // file descriptor is invalid again
      mFileDescriptor = -1;

      // not bound, listening, or connected
      mBound = false;
      mListening = false;
      mConnected = false;
   }
}

bool AbstractSocket::isBound()
{
   return mBound;
}

bool AbstractSocket::isListening()
{
   return mListening;
}

bool AbstractSocket::isConnected()
{
   return mConnected;
}

bool AbstractSocket::getLocalAddress(SocketAddress* address)
{
   Exception* exception = NULL;

   if(!isBound())
   {
      exception = new SocketException(
         "Cannot get local address for an unbound Socket!");
   }
   else
   {
      // get address structure
      socklen_t size = 130;
      char addr[size];

      // get local information
      int error = getsockname(mFileDescriptor, (sockaddr*)&addr, &size);
      if(error < 0)
      {
         exception = new SocketException(
            "Could not get Socket local address!", strerror(errno));
      }

      // convert socket address
      address->fromSockAddr((sockaddr*)&addr, size);
   }

   if(exception != NULL)
   {
      Thread::setException(exception);
   }

   return exception == NULL;
}

bool AbstractSocket::getRemoteAddress(SocketAddress* address)
{
   Exception* exception = NULL;

   if(!isConnected())
   {
      exception = new SocketException(
         "Cannot get local address for an unconnected Socket!");
   }
   else
   {
      // get address structure
      socklen_t size = 130;
      char addr[size];

      // get remote information
      int error = getpeername(mFileDescriptor, (sockaddr*)&addr, &size);
      if(error < 0)
      {
         exception = new SocketException(
            "Could not get Socket remote address!", strerror(errno));
      }
      else
      {
         // convert socket address
         address->fromSockAddr((sockaddr*)&addr, size);
      }
   }

   if(exception != NULL)
   {
      Thread::setException(exception);
   }

   return exception == NULL;
}

InputStream* AbstractSocket::getInputStream()
{
   return mInputStream;
}

OutputStream* AbstractSocket::getOutputStream()
{
   return mOutputStream;
}

void AbstractSocket::setSendTimeout(unsigned long timeout)
{
   mSendTimeout = timeout;
}

unsigned long AbstractSocket::getSendTimeout()
{
   return mSendTimeout;
}

void AbstractSocket::setReceiveTimeout(unsigned long timeout)
{
   mReceiveTimeout = timeout;
}

unsigned long AbstractSocket::getReceiveTimeout()
{
   return mReceiveTimeout;
}

unsigned int AbstractSocket::getBacklog()
{
   return mBacklog;
}

int AbstractSocket::getFileDescriptor()
{
   return mFileDescriptor;
}
<commit_msg>Fixed bug where input/output streams where not deleted properly.<commit_after>/*
 * Copyright (c) 2007 Digital Bazaar, Inc.  All rights reserved.
 */
#include "AbstractSocket.h"
#include "SocketDefinitions.h"
#include "InterruptedException.h"
#include "PeekInputStream.h"
#include "SocketInputStream.h"
#include "SocketOutputStream.h"
#include "Thread.h"

using namespace db::io;
using namespace db::net;
using namespace db::rt;

AbstractSocket::AbstractSocket()
{
   // file descriptor is invalid at this point
   mFileDescriptor = -1;

   // not bound, listening, or connected
   mBound = false;
   mListening = false;
   mConnected = false;

   // input/output uninitialized
   mInputStream = NULL;
   mOutputStream = NULL;

   // no receive or send timeouts (socket will block)
   mReceiveTimeout = 0;
   mSendTimeout = 0;

   // default backlog is 50
   mBacklog = 50;
}

AbstractSocket::~AbstractSocket()
{
   // close socket
   close();
}

bool AbstractSocket::create(int domain, int type, int protocol)
{
   bool rval = false;

   int fd = socket(domain, type, protocol);
   if(fd >= 0)
   {
      // set reuse address flag
      // disables "address already in use" errors by reclaiming ports that
      // are waiting to be cleaned up
      int reuse = 1;
      int error = setsockopt(
         fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse));
      if(error < 0)
      {
         // close socket
         close();

         Thread::setException(new SocketException(
            "Could not create Socket!", strerror(errno)));
      }
      else
      {
         mFileDescriptor = fd;
         rval = true;
      }
   }
   else
   {
      Thread::setException(new SocketException(
         "Could not create Socket!", strerror(errno)));
   }

   return rval;
}

bool AbstractSocket::select(bool read, long long timeout)
{
   Exception* exception = NULL;

   if(!Thread::interrupted(false))
   {
      // create a file descriptor set to select on
      fd_set fds;
      FD_ZERO(&fds);

      // add file descriptor to set
      FD_SET((unsigned int)mFileDescriptor, &fds);

      // "n" parameter is the highest numbered descriptor plus 1
      int n = mFileDescriptor + 1;

      int error;
      if(read)
      {
         // wait for data to arrive for reading or for an exception
         error = Thread::select(n, &fds, NULL, &fds, timeout);
      }
      else
      {
         // wait for writability or for an exception
         error = Thread::select(n, NULL, &fds, &fds, timeout);
      }

      if(error < 0)
      {
         if(errno == EINTR)
         {
            if(read)
            {
               // interrupted exception
               exception = new InterruptedException(
                  "Socket read interrupted!", strerror(errno));
            }
            else
            {
               // interrupted exception
               exception = new InterruptedException(
                  "Socket write interrupted!", strerror(errno));
            }
         }

         if(read)
         {
            // error occurred, get string message
            exception = new SocketException(
               "Could not read from Socket!", strerror(errno));
         }
         else
         {
            // error occurred, get string message
            exception = new SocketException(
               "Could not write to Socket!", strerror(errno));
         }
      }
      else if(error == 0)
      {
         if(read)
         {
            // read timeout occurred
            exception = new SocketTimeoutException(
               "Socket read timed out!", strerror(errno));
         }
         else
         {
            // write timeout occurred
            exception = new SocketTimeoutException(
               "Socket write timed out!", strerror(errno));
         }
      }
   }

   if(exception == NULL && Thread::interrupted(false))
   {
      if(read)
      {
         exception = new InterruptedException("Socket read interrupted!");
      }
      else
      {
         exception = new InterruptedException("Socket write interrupted!");
      }
   }

   if(exception != NULL)
   {
      Thread::setException(exception);
   }

   return exception == NULL;
}

bool AbstractSocket::initializeInput()
{
   if(mInputStream == NULL)
   {
      // create input stream
      mInputStream = new PeekInputStream(new SocketInputStream(this), true);
   }

   return true;
}

bool AbstractSocket::initializeOutput()
{
   if(mOutputStream == NULL)
   {
      // create output stream
      mOutputStream = new SocketOutputStream(this);
   }

   return true;
}

bool AbstractSocket::shutdownInput()
{
   // delete input stream
   if(mInputStream != NULL)
   {
      delete mInputStream;
   }

   return true;
}

bool AbstractSocket::shutdownOutput()
{
   // delete output stream
   if(mOutputStream != NULL)
   {
      delete mOutputStream;
   }

   return true;
}

bool AbstractSocket::bind(SocketAddress* address)
{
   // acquire file descriptor
   if(acquireFileDescriptor(address->getProtocol()))
   {
      // populate address structure
      unsigned int size = 130;
      char addr[size];
      address->toSockAddr((sockaddr*)&addr, size);

      // bind
      int error = ::bind(mFileDescriptor, (sockaddr*)&addr, size);
      if(error < 0)
      {
         Thread::setException(new SocketException(
            "Could not bind Socket!", strerror(errno)));
      }
      else
      {
         // initialize input and output
         initializeInput();
         initializeOutput();

         // now bound
         mBound = true;
      }
   }

   return mBound;
}

bool AbstractSocket::listen(unsigned int backlog)
{
   if(!isBound())
   {
      Thread::setException(new SocketException(
         "Cannot listen on unbound Socket!"));
   }
   else
   {
      // set backlog
      mBacklog = backlog;

      // listen
      int error = ::listen(mFileDescriptor, backlog);
      if(error < 0)
      {
         Thread::setException(new SocketException(
            "Could not listen on Socket!", strerror(errno)));
      }
      else
      {
         // now listening
         mListening = true;
      }
   }

   return mListening;
}

Socket* AbstractSocket::accept(unsigned int timeout)
{
   Socket* rval = NULL;

   if(!isListening())
   {
      Thread::setException(new SocketException(
         "Cannot accept with a non-listening Socket!"));
   }
   else
   {
      // wait for a connection
      if(select(true, timeout * 1000LL))
      {
         // accept a connection
         int fd = ::accept(mFileDescriptor, NULL, NULL);
         if(fd < 0)
         {
            Thread::setException(new SocketException(
               "Could not accept connection!", strerror(errno)));
         }
         else
         {
            // create a connected Socket
            rval = createConnectedSocket(fd);
         }
      }
   }

   return rval;
}

bool AbstractSocket::connect(SocketAddress* address, unsigned int timeout)
{
   // acquire file descriptor
   if(acquireFileDescriptor(address->getProtocol()))
   {
      // populate address structure
      unsigned int size = 130;
      char addr[size];
      address->toSockAddr((sockaddr*)&addr, size);

      // make socket non-blocking temporarily
      fcntl(mFileDescriptor, F_SETFL, O_NONBLOCK);

      // connect
      int error = ::connect(mFileDescriptor, (sockaddr*)addr, size);
      if(error < 0)
      {
         // wait until the connection can be written to
         if(select(false, timeout * 1000LL))
         {
            // get the last error on the socket
            int lastError;
            socklen_t lastErrorLength = sizeof(lastError);
            getsockopt(
               mFileDescriptor, SOL_SOCKET, SO_ERROR,
               (char*)&lastError, &lastErrorLength);
            if(lastError == 0)
            {
               // now connected and bound
               mBound = true;
               mConnected = true;
            }
            else
            {
               Thread::setException(new SocketException(
                  "Could not connect Socket! Connection refused.",
                  strerror(lastError)));
            }
         }
      }
      else
      {
         // now connected and bound
         mBound = true;
         mConnected = true;
      }

      // restore socket to blocking
      fcntl(mFileDescriptor, F_SETFL, 0);

      if(mConnected)
      {
         // initialize input and output
         initializeInput();
         initializeOutput();
      }
   }

   return mConnected;
}

bool AbstractSocket::send(const char* b, unsigned int length)
{
   Exception* exception = NULL;

   if(!isBound())
   {
      exception = new SocketException("Cannot write to unbound Socket!");
   }
   else
   {
      // send all data (send can fail to send all bytes in one go because the
      // socket send buffer was full)
      unsigned int offset = 0;
      while(exception == NULL && length > 0)
      {
         // wait for socket to become writable
         if(select(false, getSendTimeout()))
         {
            // send some data
            int bytes = ::send(mFileDescriptor, b + offset, length, 0);
            if(bytes < 0)
            {
               exception = new SocketException(
                  "Could not write to Socket!", strerror(errno));
            }
            else if(bytes > 0)
            {
               offset += bytes;
               length -= bytes;
            }
         }
         else
         {
            exception = Thread::getException();
         }
      }
   }

   if(exception != NULL)
   {
      Thread::setException(exception);
   }

   return exception == NULL;
}

int AbstractSocket::receive(char* b, unsigned int length)
{
   int rval = -1;

   if(!isBound())
   {
      Thread::setException(new SocketException(
         "Cannot read from unbound Socket!"));
   }
   else
   {
      // wait for data to become available
      if(select(true, getReceiveTimeout()))
      {
         // receive some data
         rval = ::recv(mFileDescriptor, b, length, 0);
         if(rval < -1)
         {
            rval = -1;
            Thread::setException(new SocketException(
               "Could not read from Socket!", strerror(errno)));
         }
         else if(rval == 0)
         {
            // socket is closed now
            rval = -1;
         }
      }
   }

   return rval;
}

void AbstractSocket::close()
{
   if(mFileDescriptor != -1)
   {
      // shutdown input and output
      shutdownInput();
      shutdownOutput();

      // close the socket
      ::close(mFileDescriptor);

      // file descriptor is invalid again
      mFileDescriptor = -1;

      // not bound, listening, or connected
      mBound = false;
      mListening = false;
      mConnected = false;
   }
}

bool AbstractSocket::isBound()
{
   return mBound;
}

bool AbstractSocket::isListening()
{
   return mListening;
}

bool AbstractSocket::isConnected()
{
   return mConnected;
}

bool AbstractSocket::getLocalAddress(SocketAddress* address)
{
   Exception* exception = NULL;

   if(!isBound())
   {
      exception = new SocketException(
         "Cannot get local address for an unbound Socket!");
   }
   else
   {
      // get address structure
      socklen_t size = 130;
      char addr[size];

      // get local information
      int error = getsockname(mFileDescriptor, (sockaddr*)&addr, &size);
      if(error < 0)
      {
         exception = new SocketException(
            "Could not get Socket local address!", strerror(errno));
      }

      // convert socket address
      address->fromSockAddr((sockaddr*)&addr, size);
   }

   if(exception != NULL)
   {
      Thread::setException(exception);
   }

   return exception == NULL;
}

bool AbstractSocket::getRemoteAddress(SocketAddress* address)
{
   Exception* exception = NULL;

   if(!isConnected())
   {
      exception = new SocketException(
         "Cannot get local address for an unconnected Socket!");
   }
   else
   {
      // get address structure
      socklen_t size = 130;
      char addr[size];

      // get remote information
      int error = getpeername(mFileDescriptor, (sockaddr*)&addr, &size);
      if(error < 0)
      {
         exception = new SocketException(
            "Could not get Socket remote address!", strerror(errno));
      }
      else
      {
         // convert socket address
         address->fromSockAddr((sockaddr*)&addr, size);
      }
   }

   if(exception != NULL)
   {
      Thread::setException(exception);
   }

   return exception == NULL;
}

InputStream* AbstractSocket::getInputStream()
{
   return mInputStream;
}

OutputStream* AbstractSocket::getOutputStream()
{
   return mOutputStream;
}

void AbstractSocket::setSendTimeout(unsigned long timeout)
{
   mSendTimeout = timeout;
}

unsigned long AbstractSocket::getSendTimeout()
{
   return mSendTimeout;
}

void AbstractSocket::setReceiveTimeout(unsigned long timeout)
{
   mReceiveTimeout = timeout;
}

unsigned long AbstractSocket::getReceiveTimeout()
{
   return mReceiveTimeout;
}

unsigned int AbstractSocket::getBacklog()
{
   return mBacklog;
}

int AbstractSocket::getFileDescriptor()
{
   return mFileDescriptor;
}
<|endoftext|>


<commit_before>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "mitkFileReaderRegistry.h"

#include "mitkIMimeTypeProvider.h"
#include "mitkCoreServices.h"

// Microservices
#include <usGetModuleContext.h>
#include <usModuleContext.h>
#include <usServiceProperties.h>
#include <usLDAPProp.h>

#include "itksys/SystemTools.hxx"

mitk::FileReaderRegistry::FileReaderRegistry()
{
}

mitk::FileReaderRegistry::~FileReaderRegistry()
{
  for (std::map<mitk::IFileReader*, us::ServiceObjects<mitk::IFileReader> >::iterator iter = m_ServiceObjects.begin(),
    end = m_ServiceObjects.end(); iter != end; ++iter)
  {
    iter->second.UngetService(iter->first);
  }
}

mitk::MimeType mitk::FileReaderRegistry::GetMimeTypeForFile(const std::string& path, us::ModuleContext* context)
{
  mitk::CoreServicePointer<mitk::IMimeTypeProvider> mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider(context));
  std::vector<MimeType> mimeTypes = mimeTypeProvider->GetMimeTypesForFile(path);
  if (mimeTypes.empty())
  {
    return MimeType();
  }
  else
  {
    return mimeTypes.front();
  }
}

std::vector<mitk::FileReaderRegistry::ReaderReference> mitk::FileReaderRegistry::GetReferences(const MimeType& mimeType, us::ModuleContext* context)
{
  std::string filter = us::LDAPProp(us::ServiceConstants::OBJECTCLASS()) == us_service_interface_iid<IFileReader>() &&
                       us::LDAPProp(IFileReader::PROP_MIMETYPE()) == mimeType.GetName();
  return context->GetServiceReferences<IFileReader>(filter);
}

mitk::IFileReader* mitk::FileReaderRegistry::GetReader(const mitk::FileReaderRegistry::ReaderReference& ref, us::ModuleContext* context)
{
  us::ServiceObjects<mitk::IFileReader> serviceObjects = context->GetServiceObjects(ref);
  mitk::IFileReader* reader = serviceObjects.GetService();
  m_ServiceObjects.insert(std::make_pair(reader, serviceObjects));
  return reader;
}

std::vector <mitk::IFileReader*> mitk::FileReaderRegistry::GetReaders(const MimeType& mimeType, us::ModuleContext* context )
{
  std::vector <mitk::IFileReader*> result;

  if (!mimeType.IsValid()) return result;

  std::vector <us::ServiceReference<IFileReader> > refs = GetReferences(mimeType, context);
  std::sort(refs.begin(), refs.end());

  result.reserve(refs.size());

  // Translate List of ServiceRefs to List of Pointers
  for (std::vector<us::ServiceReference<IFileReader> >::const_reverse_iterator iter = refs.rbegin(), end = refs.rend();
       iter != end; ++iter)
  {
    us::ServiceObjects<mitk::IFileReader> serviceObjects = context->GetServiceObjects(*iter);
    mitk::IFileReader* reader = serviceObjects.GetService();
    m_ServiceObjects.insert(std::make_pair(reader, serviceObjects));
    result.push_back(reader);
  }

  return result;
}

void mitk::FileReaderRegistry::UngetReader(mitk::IFileReader* reader)
{
  std::map<mitk::IFileReader*, us::ServiceObjects<mitk::IFileReader> >::iterator readerIter =
    m_ServiceObjects.find(reader);
  if (readerIter != m_ServiceObjects.end())
  {
    readerIter->second.UngetService(reader);
    m_ServiceObjects.erase(readerIter);
  }
}

void mitk::FileReaderRegistry::UngetReaders(const std::vector<mitk::IFileReader*>& readers)
{
  for (std::vector<mitk::IFileReader*>::const_iterator iter = readers.begin(), end = readers.end();
    iter != end; ++iter)
  {
    this->UngetReader(*iter);
  }
}
<commit_msg>Added a check to the FileReader Registry<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "mitkFileReaderRegistry.h"

#include "mitkIMimeTypeProvider.h"
#include "mitkCoreServices.h"

// Microservices
#include <usGetModuleContext.h>
#include <usModuleContext.h>
#include <usServiceProperties.h>
#include <usLDAPProp.h>

#include "itksys/SystemTools.hxx"

mitk::FileReaderRegistry::FileReaderRegistry()
{
}

mitk::FileReaderRegistry::~FileReaderRegistry()
{
  for (std::map<mitk::IFileReader*, us::ServiceObjects<mitk::IFileReader> >::iterator iter = m_ServiceObjects.begin(),
    end = m_ServiceObjects.end(); iter != end; ++iter)
  {
    iter->second.UngetService(iter->first);
  }
}

mitk::MimeType mitk::FileReaderRegistry::GetMimeTypeForFile(const std::string& path, us::ModuleContext* context)
{
  if (path.empty()){
    MITK_ERROR << "Warning: FileReaderRegistry::GetMimeTypeForFile was called with empty path. Returning empty MimeType, please report this error to the developers.";
    return MimeType();
  }

  mitk::CoreServicePointer<mitk::IMimeTypeProvider> mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider(context));
  std::vector<MimeType> mimeTypes = mimeTypeProvider->GetMimeTypesForFile(path);
  if (mimeTypes.empty())
  {
    return MimeType();
  }
  else
  {
    return mimeTypes.front();
  }
}

std::vector<mitk::FileReaderRegistry::ReaderReference> mitk::FileReaderRegistry::GetReferences(const MimeType& mimeType, us::ModuleContext* context)
{
  std::string filter = us::LDAPProp(us::ServiceConstants::OBJECTCLASS()) == us_service_interface_iid<IFileReader>() &&
                       us::LDAPProp(IFileReader::PROP_MIMETYPE()) == mimeType.GetName();
  return context->GetServiceReferences<IFileReader>(filter);
}

mitk::IFileReader* mitk::FileReaderRegistry::GetReader(const mitk::FileReaderRegistry::ReaderReference& ref, us::ModuleContext* context)
{
  us::ServiceObjects<mitk::IFileReader> serviceObjects = context->GetServiceObjects(ref);
  mitk::IFileReader* reader = serviceObjects.GetService();
  m_ServiceObjects.insert(std::make_pair(reader, serviceObjects));
  return reader;
}

std::vector <mitk::IFileReader*> mitk::FileReaderRegistry::GetReaders(const MimeType& mimeType, us::ModuleContext* context )
{
  std::vector <mitk::IFileReader*> result;

  if (!mimeType.IsValid()) return result;

  std::vector <us::ServiceReference<IFileReader> > refs = GetReferences(mimeType, context);
  std::sort(refs.begin(), refs.end());

  result.reserve(refs.size());

  // Translate List of ServiceRefs to List of Pointers
  for (std::vector<us::ServiceReference<IFileReader> >::const_reverse_iterator iter = refs.rbegin(), end = refs.rend();
       iter != end; ++iter)
  {
    us::ServiceObjects<mitk::IFileReader> serviceObjects = context->GetServiceObjects(*iter);
    mitk::IFileReader* reader = serviceObjects.GetService();
    m_ServiceObjects.insert(std::make_pair(reader, serviceObjects));
    result.push_back(reader);
  }

  return result;
}

void mitk::FileReaderRegistry::UngetReader(mitk::IFileReader* reader)
{
  std::map<mitk::IFileReader*, us::ServiceObjects<mitk::IFileReader> >::iterator readerIter =
    m_ServiceObjects.find(reader);
  if (readerIter != m_ServiceObjects.end())
  {
    readerIter->second.UngetService(reader);
    m_ServiceObjects.erase(readerIter);
  }
}

void mitk::FileReaderRegistry::UngetReaders(const std::vector<mitk::IFileReader*>& readers)
{
  for (std::vector<mitk::IFileReader*>::const_iterator iter = readers.begin(), end = readers.end();
    iter != end; ++iter)
  {
    this->UngetReader(*iter);
  }
}
<|endoftext|>