<commit_before>// File__Duplicate - Duplication of some formats
// Copyright (C) 2007-2009 Jerome Martinez, Zen@MediaArea.net
//
// This library is free software: you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library. If not, see <http://www.gnu.org/licenses/>.
//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Duplication helper for some specific formats
//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//---------------------------------------------------------------------------
// Compilation conditions
#include "MediaInfo/Setup.h"
#ifdef __BORLANDC__
    #pragma hdrstop
#endif
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#include "MediaInfo/Multiple/File_MpegTs.h"
#include "MediaInfo/MediaInfo_Config.h"
#include "MediaInfo/MediaInfo_Config_MediaInfo.h"
#include "ZenLib/ZtringList.h"
#include "ZenLib/File.h"
using namespace ZenLib;
using namespace std;
//---------------------------------------------------------------------------

namespace MediaInfoLib
{

//***************************************************************************
// Constructor/Destructor
//***************************************************************************

void File_MpegTs::File__Duplicate_Delete ()
{
    if (Complete_Stream)
    {
        std::map<const String, File__Duplicate_MpegTs*>::iterator Duplicates_Temp=Complete_Stream->Duplicates.begin();
        while (Duplicates_Temp!=Complete_Stream->Duplicates.end())
        {
            delete Duplicates_Temp->second; //Duplicates_Temp->second=NULL
            Duplicates_Temp++;
        }
        Complete_Stream->Duplicates.clear();
    }
}

//***************************************************************************
// Format
//***************************************************************************

void File_MpegTs::File__Duplicate_Read_Buffer_Finalize ()
{
    if (!File_Name.empty()) //Only if this is not a buffer, with buffer we can have more data
        Complete_Stream->Duplicates_Speed_FromPID.clear();
}

//***************************************************************************
// Options
//***************************************************************************

//---------------------------------------------------------------------------
void File_MpegTs::Option_Manage()
{
    if (Complete_Stream && !Complete_Stream->Streams.empty())
    {
        //File_Filter configuration
        if (Config->File_Filter_HasChanged())
        {
            bool Searching_Payload_Start=!Config->File_Filter_Get();
            for (int32u Pos=0x01; Pos<0x10; Pos++)
                Complete_Stream->Streams[Pos].Searching_Payload_Start_Set(Searching_Payload_Start); //base PID depends of File_Filter configuration
            Complete_Stream->Streams[0x00].Searching_Payload_Start_Set(true); //program_map
        }

        //File__Duplicate configuration
        if (File__Duplicate_HasChanged())
        {
            for (size_t Pos=0x0000; Pos<0x2000; Pos++)
                Complete_Stream->Streams[Pos].ShouldDuplicate=false;
            Complete_Stream->Streams[0x0000].ShouldDuplicate=true;

            //For each program
            for (complete_stream::transport_stream::programs::iterator Program=Complete_Stream->Transport_Streams[Complete_Stream->transport_stream_id].Programs.begin(); Program!=Complete_Stream->Transport_Streams[Complete_Stream->transport_stream_id].Programs.end(); Program++)
            {
                //Do we want this program?
                bool Wanted=false;
                for (std::map<const String, File__Duplicate_MpegTs*>::iterator Duplicate=Complete_Stream->Duplicates.begin(); Duplicate!=Complete_Stream->Duplicates.end(); Duplicate++)
                {
                    if (Duplicate->second->Wanted_program_numbers.find(Program->first)!=Duplicate->second->Wanted_program_numbers.end())
                        Wanted=true;
                    if (Duplicate->second->Wanted_program_map_PIDs.find(Program->second.pid)!=Duplicate->second->Wanted_program_map_PIDs.end())
                        Wanted=true;
                }

                //Enabling it if wanted
                if (Wanted)
                {
                    Complete_Stream->Streams[Program->second.pid].ShouldDuplicate=true;
                    for (size_t Pos=0; Pos<Program->second.elementary_PIDs.size(); Pos++)
                        Complete_Stream->Streams[Program->second.elementary_PIDs[Pos]].ShouldDuplicate=true;
                }
            }
        }
    }
}

//***************************************************************************
// Set
//***************************************************************************

//---------------------------------------------------------------------------
bool File_MpegTs::File__Duplicate_Set (const Ztring &Value)
{
    //Form: "Code;Target"                           <--Generic
    //Form: "program_number" or                     <--clear it
    //Form: "program_number;file" or                <--the exported filename is filename.program_number
    //Form: "program_number;file://filename" or     <--the exported filename is specified by user
    //Form: "program_number;memory" or              <--This will be a MediaInfo memory block
    //Form: "program_number;memory://pointer:size"  <--Memory block is specified by user
    //WARNING: program_number & pointer must be in ***DECIMAL*** format.
    //Example: "451;memory://123456789:1316"
    ZtringList List(Value);

    //Backward compatibility
    bool Orders_ToRemove_Global=false;

    //Searching Target
    bool IsForUs=true; //True by default for backward compatibility
    std::vector<ZtringList::iterator> Targets_ToAdd;
    std::vector<ZtringList::iterator> Targets_ToRemove;
    std::vector<ZtringList::iterator> Orders_ToAdd;
    std::vector<ZtringList::iterator> Orders_ToRemove;
    for (ZtringList::iterator Current=List.begin(); Current<List.end(); Current++)
    {
        //Detecting if we want to remove
        bool ToRemove=false;
        if (Current->find(_T('-'))==0)
        {
            ToRemove=true;
            Current->erase(Current->begin());
        }

        //Managing targets
        if (Current->find(_T("file:"))==0
         || Current->find(_T("memory:"))==0)
            (ToRemove?Targets_ToRemove:Targets_ToAdd).push_back(Current);
        //Parser name
        else if (Current->find(_T("parser="))==0)
        {
            if (*Current==_T("parser=MpegTs"))
                IsForUs=true;
            else
                IsForUs=false; //Backward compatibility with missing parser name
        }
        //Backward compatibility with "0"
        else if (*Current==_T("0"))
            Orders_ToRemove_Global=true;
        //Managing orders
        else
            (ToRemove?Orders_ToRemove:Orders_ToAdd).push_back(Current);
    }

    //For us?
    if (!IsForUs)
        return false;

    //Backward compatibility
    if (Orders_ToRemove_Global) //with "0"
    {
        for (std::vector<ZtringList::iterator>::iterator Order=Orders_ToAdd.begin(); Order<Orders_ToAdd.end(); Order++)
            Orders_ToRemove.push_back(*Order);
        Orders_ToAdd.clear();
    }

    //For each target to add
    for (std::vector<ZtringList::iterator>::iterator Target=Targets_ToAdd.begin(); Target<Targets_ToAdd.end(); Target++)
    {
        //Adding the target if it does not exist yet
        if (Complete_Stream->Duplicates.find(**Target)==Complete_Stream->Duplicates.end())
        {
            Complete_Stream->Duplicates[**Target]=new File__Duplicate_MpegTs(**Target);
            size_t Pos=Config->File__Duplicate_Memory_Indexes_Get(**Target);
            if (Pos!=Error)
            {
                if (Pos>=Complete_Stream->Duplicates_Speed.size())
                    Complete_Stream->Duplicates_Speed.resize(Pos+1);
                Complete_Stream->Duplicates_Speed[Pos]=Complete_Stream->Duplicates[**Target];
            }
        }

        //For each order to add
        for (std::vector<ZtringList::iterator>::iterator Order=Orders_ToAdd.begin(); Order<Orders_ToAdd.end(); Order++)
            Complete_Stream->Duplicates[**Target]->Configure(**Order, false);

        //For each order to remove
        for (std::vector<ZtringList::iterator>::iterator Order=Orders_ToRemove.begin(); Order<Orders_ToRemove.end(); Order++)
            Complete_Stream->Duplicates[**Target]->Configure(**Order, true);
    }

    //For each target to remove
    for (std::vector<ZtringList::iterator>::iterator Target=Targets_ToRemove.begin(); Target<Targets_ToRemove.end(); Target++)
    {
        std::map<const String, File__Duplicate_MpegTs*>::iterator Pointer=Complete_Stream->Duplicates.find(**Target);
        if (Pointer!=Complete_Stream->Duplicates.end())
        {
            //Duplicates_Speed
            for (std::vector<File__Duplicate_MpegTs*>::iterator Duplicate=Complete_Stream->Duplicates_Speed.begin(); Duplicate<Complete_Stream->Duplicates_Speed.end(); Duplicate++)
                if (*Duplicate==Pointer->second)
                    *Duplicate=NULL;

            //Duplicates_Speed_FromPID
            for (std::vector<std::vector<File__Duplicate_MpegTs*> >::iterator Duplicate_FromPID=Complete_Stream->Duplicates_Speed_FromPID.begin(); Duplicate_FromPID<Complete_Stream->Duplicates_Speed_FromPID.end(); Duplicate_FromPID++)
                for (std::vector<File__Duplicate_MpegTs*>::iterator Duplicate=Duplicate_FromPID->begin(); Duplicate<Duplicate_FromPID->end(); Duplicate++)
                    if (*Duplicate==Pointer->second)
                        *Duplicate=NULL;

            //Duplicate
            Complete_Stream->Duplicates.erase(**Target);
        }
    }

    //Informing the status has changed
    Complete_Stream->File__Duplicate_HasChanged_=true;
    if (Complete_Stream->Duplicates_Speed_FromPID.empty())
        Complete_Stream->Duplicates_Speed_FromPID.resize(0x2000);

    Complete_Stream->Duplicates_Speed_FromPID[0x00]=Complete_Stream->Duplicates_Speed;

    return true;
}

//***************************************************************************
// Get
//***************************************************************************

bool File_MpegTs::File__Duplicate_Get_From_PID (int16u PID)
{
    if (Complete_Stream->Duplicates_Speed_FromPID.empty())
        return false;
    return !Complete_Stream->Duplicates_Speed_FromPID[PID].empty();
}

//***************************************************************************
// Write
//***************************************************************************

void File_MpegTs::File__Duplicate_Write (int16u PID)
{
    const int8u* ToAdd=Buffer+Buffer_Offset-(size_t)Header_Size;
    size_t ToAdd_Size=(size_t)(Element_Size+Header_Size);

    std::vector<File__Duplicate_MpegTs*> &Dup_FromPID=Complete_Stream->Duplicates_Speed_FromPID[PID];
    size_t Size=Complete_Stream->Duplicates_Speed_FromPID[PID].size();
    bool ToUpdate=false;
    for (size_t Pos=0; Pos<Size; Pos++)
        if (Dup_FromPID[Pos] && Dup_FromPID[Pos]->Write(PID, ToAdd, ToAdd_Size))
            ToUpdate=true;
    if (ToUpdate)
    {
        Complete_Stream->Duplicates_Speed_FromPID.clear();
        Complete_Stream->Duplicates_Speed_FromPID.resize(0x2000);
        Complete_Stream->Duplicates_Speed_FromPID[0x0000]=Complete_Stream->Duplicates_Speed;
        size_t Size=Complete_Stream->Duplicates_Speed.size();
        for (size_t Pos=0; Pos<Size; Pos++)
        {
            File__Duplicate_MpegTs* Dup=Complete_Stream->Duplicates_Speed[Pos];
            size_t program_map_PIDs_Size=Complete_Stream->Duplicates_Speed[Pos]->program_map_PIDs.size();
            for (size_t program_map_PIDs_Pos=0; program_map_PIDs_Pos<program_map_PIDs_Size; program_map_PIDs_Pos++)
                if (Dup->program_map_PIDs[program_map_PIDs_Pos])
                    Complete_Stream->Duplicates_Speed_FromPID[program_map_PIDs_Pos].push_back(Dup);
            size_t elementary_PIDs_Size=Complete_Stream->Duplicates_Speed[Pos]->program_map_PIDs.size();
            for (size_t elementary_PIDs_Pos=0; elementary_PIDs_Pos<elementary_PIDs_Size; elementary_PIDs_Pos++)
                if (Dup->elementary_PIDs[elementary_PIDs_Pos])
                    Complete_Stream->Duplicates_Speed_FromPID[elementary_PIDs_Pos].push_back(Dup);
        }
    }
}

//***************************************************************************
// Output_Buffer
//***************************************************************************

//---------------------------------------------------------------------------
size_t File_MpegTs::Output_Buffer_Get (const String &Code)
{
    std::map<const String, File__Duplicate_MpegTs*>::iterator Stream=Complete_Stream->Duplicates.find(Code);
    if (Stream==Complete_Stream->Duplicates.end())
        return 0;

    return Stream->second->Output_Buffer_Get();

    //Was used for test (AVC output), but is a lot too slow, must find something else
    /*
    if (size_t Size=Stream->second->Output_Buffer_Get())
        return Size;

    //Parsing Parsers
    for (size_t Stream_Pos=0; Stream_Pos<Streams.size(); Stream_Pos++)
        if (Streams[Stream_Pos].Parser)
            if (size_t Size=Streams[Stream_Pos].Parser->Output_Buffer_Get(Code))
                return Size;

    return 0;
    */
}

//---------------------------------------------------------------------------
size_t File_MpegTs::Output_Buffer_Get (size_t Pos)
{
    if (Pos<Complete_Stream->Duplicates_Speed.size() && Complete_Stream->Duplicates_Speed[Pos]!=NULL)
        if (size_t Size=Complete_Stream->Duplicates_Speed[Pos]->Output_Buffer_Get())
            return Size;

    //Parsing Parsers
    /*
    for (size_t Stream_Pos=0; Stream_Pos<Complete_Stream->Streams.size(); Stream_Pos++)
        if (Complete_Stream->Streams[Stream_Pos].Parser)
            if (size_t Size=Complete_Stream->Streams[Stream_Pos].Parser->Output_Buffer_Get(Pos))
            {
                //Optimization
                //if (Output_Buffer_Get_Pos.size()<=Pos)
                //    Output_Buffer_Get_Pos.resize(Pos+1, (int16u)-1);
                //Output_Buffer_Get_Pos[Pos]=Stream_Pos;

                return Size;
            }
    */

    return 0;
}

} //NameSpace

<commit_msg><commit_after>// File__Duplicate - Duplication of some formats
// Copyright (C) 2007-2009 Jerome Martinez, Zen@MediaArea.net
//
// This library is free software: you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library. If not, see <http://www.gnu.org/licenses/>.
//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Duplication helper for some specific formats
//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//---------------------------------------------------------------------------
// Compilation conditions
#include "MediaInfo/Setup.h"
#ifdef __BORLANDC__
    #pragma hdrstop
#endif
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#if defined(MEDIAINFO_MPEGTS_YES)
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#include "MediaInfo/Multiple/File_MpegTs.h"
#include "MediaInfo/MediaInfo_Config.h"
#include "MediaInfo/MediaInfo_Config_MediaInfo.h"
#include "ZenLib/ZtringList.h"
#include "ZenLib/File.h"
using namespace ZenLib;
using namespace std;
//---------------------------------------------------------------------------

namespace MediaInfoLib
{

//***************************************************************************
// Constructor/Destructor
//***************************************************************************

void File_MpegTs::File__Duplicate_Delete ()
{
    if (Complete_Stream)
    {
        std::map<const String, File__Duplicate_MpegTs*>::iterator Duplicates_Temp=Complete_Stream->Duplicates.begin();
        while (Duplicates_Temp!=Complete_Stream->Duplicates.end())
        {
            delete Duplicates_Temp->second; //Duplicates_Temp->second=NULL
            Duplicates_Temp++;
        }
        Complete_Stream->Duplicates.clear();
    }
}

//***************************************************************************
// Format
//***************************************************************************

void File_MpegTs::File__Duplicate_Read_Buffer_Finalize ()
{
    if (!File_Name.empty()) //Only if this is not a buffer, with buffer we can have more data
        Complete_Stream->Duplicates_Speed_FromPID.clear();
}

//***************************************************************************
// Options
//***************************************************************************

//---------------------------------------------------------------------------
void File_MpegTs::Option_Manage()
{
    if (Complete_Stream && !Complete_Stream->Streams.empty())
    {
        //File_Filter configuration
        if (Config->File_Filter_HasChanged())
        {
            bool Searching_Payload_Start=!Config->File_Filter_Get();
            for (int32u Pos=0x01; Pos<0x10; Pos++)
                Complete_Stream->Streams[Pos].Searching_Payload_Start_Set(Searching_Payload_Start); //base PID depends of File_Filter configuration
            Complete_Stream->Streams[0x00].Searching_Payload_Start_Set(true); //program_map
        }

        //File__Duplicate configuration
        if (File__Duplicate_HasChanged())
        {
            for (size_t Pos=0x0000; Pos<0x2000; Pos++)
                Complete_Stream->Streams[Pos].ShouldDuplicate=false;
            Complete_Stream->Streams[0x0000].ShouldDuplicate=true;

            //For each program
            for (complete_stream::transport_stream::programs::iterator Program=Complete_Stream->Transport_Streams[Complete_Stream->transport_stream_id].Programs.begin(); Program!=Complete_Stream->Transport_Streams[Complete_Stream->transport_stream_id].Programs.end(); Program++)
            {
                //Do we want this program?
                bool Wanted=false;
                for (std::map<const String, File__Duplicate_MpegTs*>::iterator Duplicate=Complete_Stream->Duplicates.begin(); Duplicate!=Complete_Stream->Duplicates.end(); Duplicate++)
                {
                    if (Duplicate->second->Wanted_program_numbers.find(Program->first)!=Duplicate->second->Wanted_program_numbers.end())
                        Wanted=true;
                    if (Duplicate->second->Wanted_program_map_PIDs.find(Program->second.pid)!=Duplicate->second->Wanted_program_map_PIDs.end())
                        Wanted=true;
                }

                //Enabling it if wanted
                if (Wanted)
                {
                    Complete_Stream->Streams[Program->second.pid].ShouldDuplicate=true;
                    for (size_t Pos=0; Pos<Program->second.elementary_PIDs.size(); Pos++)
                        Complete_Stream->Streams[Program->second.elementary_PIDs[Pos]].ShouldDuplicate=true;
                }
            }
        }
    }
}

//***************************************************************************
// Set
//***************************************************************************

//---------------------------------------------------------------------------
bool File_MpegTs::File__Duplicate_Set (const Ztring &Value)
{
    //Form: "Code;Target"                           <--Generic
    //Form: "program_number" or                     <--clear it
    //Form: "program_number;file" or                <--the exported filename is filename.program_number
    //Form: "program_number;file://filename" or     <--the exported filename is specified by user
    //Form: "program_number;memory" or              <--This will be a MediaInfo memory block
    //Form: "program_number;memory://pointer:size"  <--Memory block is specified by user
    //WARNING: program_number & pointer must be in ***DECIMAL*** format.
    //Example: "451;memory://123456789:1316"
    ZtringList List(Value);

    //Backward compatibility
    bool Orders_ToRemove_Global=false;

    //Searching Target
    bool IsForUs=true; //True by default for backward compatibility
    std::vector<ZtringList::iterator> Targets_ToAdd;
    std::vector<ZtringList::iterator> Targets_ToRemove;
    std::vector<ZtringList::iterator> Orders_ToAdd;
    std::vector<ZtringList::iterator> Orders_ToRemove;
    for (ZtringList::iterator Current=List.begin(); Current<List.end(); Current++)
    {
        //Detecting if we want to remove
        bool ToRemove=false;
        if (Current->find(_T('-'))==0)
        {
            ToRemove=true;
            Current->erase(Current->begin());
        }

        //Managing targets
        if (Current->find(_T("file:"))==0
         || Current->find(_T("memory:"))==0)
            (ToRemove?Targets_ToRemove:Targets_ToAdd).push_back(Current);
        //Parser name
        else if (Current->find(_T("parser="))==0)
        {
            if (*Current==_T("parser=MpegTs"))
                IsForUs=true;
            else
                IsForUs=false; //Backward compatibility with missing parser name
        }
        //Backward compatibility with "0"
        else if (*Current==_T("0"))
            Orders_ToRemove_Global=true;
        //Managing orders
        else
            (ToRemove?Orders_ToRemove:Orders_ToAdd).push_back(Current);
    }

    //For us?
    if (!IsForUs)
        return false;

    //Backward compatibility
    if (Orders_ToRemove_Global) //with "0"
    {
        for (std::vector<ZtringList::iterator>::iterator Order=Orders_ToAdd.begin(); Order<Orders_ToAdd.end(); Order++)
            Orders_ToRemove.push_back(*Order);
        Orders_ToAdd.clear();
    }

    //For each target to add
    for (std::vector<ZtringList::iterator>::iterator Target=Targets_ToAdd.begin(); Target<Targets_ToAdd.end(); Target++)
    {
        //Adding the target if it does not exist yet
        if (Complete_Stream->Duplicates.find(**Target)==Complete_Stream->Duplicates.end())
        {
            Complete_Stream->Duplicates[**Target]=new File__Duplicate_MpegTs(**Target);
            size_t Pos=Config->File__Duplicate_Memory_Indexes_Get(**Target);
            if (Pos!=Error)
            {
                if (Pos>=Complete_Stream->Duplicates_Speed.size())
                    Complete_Stream->Duplicates_Speed.resize(Pos+1);
                Complete_Stream->Duplicates_Speed[Pos]=Complete_Stream->Duplicates[**Target];
            }
        }

        //For each order to add
        for (std::vector<ZtringList::iterator>::iterator Order=Orders_ToAdd.begin(); Order<Orders_ToAdd.end(); Order++)
            Complete_Stream->Duplicates[**Target]->Configure(**Order, false);

        //For each order to remove
        for (std::vector<ZtringList::iterator>::iterator Order=Orders_ToRemove.begin(); Order<Orders_ToRemove.end(); Order++)
            Complete_Stream->Duplicates[**Target]->Configure(**Order, true);
    }

    //For each target to remove
    for (std::vector<ZtringList::iterator>::iterator Target=Targets_ToRemove.begin(); Target<Targets_ToRemove.end(); Target++)
    {
        std::map<const String, File__Duplicate_MpegTs*>::iterator Pointer=Complete_Stream->Duplicates.find(**Target);
        if (Pointer!=Complete_Stream->Duplicates.end())
        {
            //Duplicates_Speed
            for (std::vector<File__Duplicate_MpegTs*>::iterator Duplicate=Complete_Stream->Duplicates_Speed.begin(); Duplicate<Complete_Stream->Duplicates_Speed.end(); Duplicate++)
                if (*Duplicate==Pointer->second)
                    *Duplicate=NULL;

            //Duplicates_Speed_FromPID
            for (std::vector<std::vector<File__Duplicate_MpegTs*> >::iterator Duplicate_FromPID=Complete_Stream->Duplicates_Speed_FromPID.begin(); Duplicate_FromPID<Complete_Stream->Duplicates_Speed_FromPID.end(); Duplicate_FromPID++)
                for (std::vector<File__Duplicate_MpegTs*>::iterator Duplicate=Duplicate_FromPID->begin(); Duplicate<Duplicate_FromPID->end(); Duplicate++)
                    if (*Duplicate==Pointer->second)
                        *Duplicate=NULL;

            //Duplicate
            Complete_Stream->Duplicates.erase(**Target);
        }
    }

    //Informing the status has changed
    Complete_Stream->File__Duplicate_HasChanged_=true;
    if (Complete_Stream->Duplicates_Speed_FromPID.empty())
        Complete_Stream->Duplicates_Speed_FromPID.resize(0x2000);

    Complete_Stream->Duplicates_Speed_FromPID[0x00]=Complete_Stream->Duplicates_Speed;

    return true;
}

//***************************************************************************
// Get
//***************************************************************************

bool File_MpegTs::File__Duplicate_Get_From_PID (int16u PID)
{
    if (Complete_Stream->Duplicates_Speed_FromPID.empty())
        return false;
    return !Complete_Stream->Duplicates_Speed_FromPID[PID].empty();
}

//***************************************************************************
// Write
//***************************************************************************

void File_MpegTs::File__Duplicate_Write (int16u PID)
{
    const int8u* ToAdd=Buffer+Buffer_Offset-(size_t)Header_Size;
    size_t ToAdd_Size=(size_t)(Element_Size+Header_Size);

    std::vector<File__Duplicate_MpegTs*> &Dup_FromPID=Complete_Stream->Duplicates_Speed_FromPID[PID];
    size_t Size=Complete_Stream->Duplicates_Speed_FromPID[PID].size();
    bool ToUpdate=false;
    for (size_t Pos=0; Pos<Size; Pos++)
        if (Dup_FromPID[Pos] && Dup_FromPID[Pos]->Write(PID, ToAdd, ToAdd_Size))
            ToUpdate=true;
    if (ToUpdate)
    {
        Complete_Stream->Duplicates_Speed_FromPID.clear();
        Complete_Stream->Duplicates_Speed_FromPID.resize(0x2000);
        Complete_Stream->Duplicates_Speed_FromPID[0x0000]=Complete_Stream->Duplicates_Speed;
        size_t Size=Complete_Stream->Duplicates_Speed.size();
        for (size_t Pos=0; Pos<Size; Pos++)
        {
            File__Duplicate_MpegTs* Dup=Complete_Stream->Duplicates_Speed[Pos];
            size_t program_map_PIDs_Size=Complete_Stream->Duplicates_Speed[Pos]->program_map_PIDs.size();
            for (size_t program_map_PIDs_Pos=0; program_map_PIDs_Pos<program_map_PIDs_Size; program_map_PIDs_Pos++)
                if (Dup->program_map_PIDs[program_map_PIDs_Pos])
                    Complete_Stream->Duplicates_Speed_FromPID[program_map_PIDs_Pos].push_back(Dup);
            size_t elementary_PIDs_Size=Complete_Stream->Duplicates_Speed[Pos]->program_map_PIDs.size();
            for (size_t elementary_PIDs_Pos=0; elementary_PIDs_Pos<elementary_PIDs_Size; elementary_PIDs_Pos++)
                if (Dup->elementary_PIDs[elementary_PIDs_Pos])
                    Complete_Stream->Duplicates_Speed_FromPID[elementary_PIDs_Pos].push_back(Dup);
        }
    }
}

//***************************************************************************
// Output_Buffer
//***************************************************************************

//---------------------------------------------------------------------------
size_t File_MpegTs::Output_Buffer_Get (const String &Code)
{
    std::map<const String, File__Duplicate_MpegTs*>::iterator Stream=Complete_Stream->Duplicates.find(Code);
    if (Stream==Complete_Stream->Duplicates.end())
        return 0;

    return Stream->second->Output_Buffer_Get();

    //Was used for test (AVC output), but is a lot too slow, must find something else
    /*
    if (size_t Size=Stream->second->Output_Buffer_Get())
        return Size;

    //Parsing Parsers
    for (size_t Stream_Pos=0; Stream_Pos<Streams.size(); Stream_Pos++)
        if (Streams[Stream_Pos].Parser)
            if (size_t Size=Streams[Stream_Pos].Parser->Output_Buffer_Get(Code))
                return Size;

    return 0;
    */
}

//---------------------------------------------------------------------------
size_t File_MpegTs::Output_Buffer_Get (size_t Pos)
{
    if (Pos<Complete_Stream->Duplicates_Speed.size() && Complete_Stream->Duplicates_Speed[Pos]!=NULL)
        if (size_t Size=Complete_Stream->Duplicates_Speed[Pos]->Output_Buffer_Get())
            return Size;

    //Parsing Parsers
    /*
    for (size_t Stream_Pos=0; Stream_Pos<Complete_Stream->Streams.size(); Stream_Pos++)
        if (Complete_Stream->Streams[Stream_Pos].Parser)
            if (size_t Size=Complete_Stream->Streams[Stream_Pos].Parser->Output_Buffer_Get(Pos))
            {
                //Optimization
                //if (Output_Buffer_Get_Pos.size()<=Pos)
                //    Output_Buffer_Get_Pos.resize(Pos+1, (int16u)-1);
                //Output_Buffer_Get_Pos[Pos]=Stream_Pos;

                return Size;
            }
    */

    return 0;
}

} //NameSpace

#endif //MEDIAINFO_MPEGTS_YES

<|endoftext|>


<commit_before>/*******************************************************************************
 *
 * MIT License
 *
 * Copyright 2019-2020 Advanced Micro Devices, Inc.
 *
 * 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.
 *
 *******************************************************************************/

#pragma once

#include <hip/hip_runtime.h>
#include <hip/hip_runtime_api.h>
#include <sstream>
#include <stdexcept>

#include <Tensile/TensorDescriptor.hpp>
#include <Tensile/Utils.hpp>

#define HIP_CHECK_EXC(expr)                                                                       \
    do                                                                                \
    {                                                                                \
        hipError_t e = (expr);                                                                    \
        if(e)                                                                                \
        {                                                                                \
            const char*        errName = hipGetErrorName(e);                                      \
            const char*        errMsg  = hipGetErrorString(e);                                    \
            std::ostringstream msg;                                                               \
            msg << "Error " << e << "(" << errName << ") " << __FILE__ << ":" << __LINE__ << ": " \
                << std::endl                                                                      \
                << #expr << std::endl                                                             \
                << errMsg << std::endl;                                                           \
            throw std::runtime_error(msg.str());                                                  \
        }                                                                                \
    } while(0)

#define HIP_CHECK_EXC_MESSAGE(expr, message)                                                      \
    do                                                                                \
    {                                                                                \
        hipError_t e = (expr);                                                                    \
        if(e)                                                                                \
        {                                                                                \
            const char*        errName = hipGetErrorName(e);                                      \
            const char*        errMsg  = hipGetErrorString(e);                                    \
            std::ostringstream msg;                                                               \
            msg << "Error " << e << "(" << errName << ") " << __FILE__ << ":" << __LINE__ << ": " \
                << std::endl                                                                      \
                << #expr << std::endl                                                             \
                << errMsg << std::endl                                                            \
                << (message) << std::endl;                                                        \
            throw std::runtime_error(msg.str());                                                  \
        }                                                                                \
    } while(0)

namespace Tensile
{
    namespace hip
    {
        template <typename T>
        void CopyTensor(T*                      dst,
                        T const*                src,
                        TensorDescriptor const& desc,
                        hipMemcpyKind           direction,
                        hipStream_t             stream = 0)
        {
            if(desc.dimensions() == 0 || desc.totalLogicalElements() == 0)
                return;

            auto const&         sizes   = desc.sizes();
            auto const&         strides = desc.strides();
            std::vector<size_t> coord(desc.dimensions(), 0);

            size_t contiguousDimensions = 0;
            size_t expectedStride       = 1;

            // Optimize the number of copy operations by coalescing all the
            // dimensions that are contiguous in memory.
            for(size_t i = 0; i < desc.dimensions(); i++)
            {
                contiguousDimensions = i + 1;

                if(strides[i] > expectedStride)
                    break;

                if(i < desc.dimensions() - 1)
                    expectedStride = strides[i] * sizes[i + 1];
            }

            auto copyCount = CoordCount(sizes.begin() + contiguousDimensions, sizes.end());

            size_t maxStride
                = *std::max_element(strides.begin(), strides.begin() + contiguousDimensions);
            size_t copyBytes = maxStride * sizes.at(contiguousDimensions - 1) * sizeof(T);

            for(size_t idx = 0; idx < copyCount; idx++)
            {
                CoordNumbered(idx,
                              coord.begin() + contiguousDimensions,
                              coord.end(),
                              sizes.begin() + contiguousDimensions,
                              sizes.end());

                auto beginOffset = desc.index(coord);

                HIP_CHECK_EXC(hipMemcpyAsync(
                    dst + beginOffset, src + beginOffset, copyBytes, direction, stream));
            }
        }
    } // namespace hip
} // namespace Tensile
<commit_msg>Fix CopyTensor bugs: calculate wrong dimention index for continue memory block which would cause Out-of-boundary access<commit_after>/*******************************************************************************
 *
 * MIT License
 *
 * Copyright 2019-2020 Advanced Micro Devices, Inc.
 *
 * 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.
 *
 *******************************************************************************/

#pragma once

#include <hip/hip_runtime.h>
#include <hip/hip_runtime_api.h>
#include <sstream>
#include <stdexcept>

#include <Tensile/TensorDescriptor.hpp>
#include <Tensile/Utils.hpp>

#define HIP_CHECK_EXC(expr)                                                                       \
    do                                                                                \
    {                                                                                \
        hipError_t e = (expr);                                                                    \
        if(e)                                                                                \
        {                                                                                \
            const char*        errName = hipGetErrorName(e);                                      \
            const char*        errMsg  = hipGetErrorString(e);                                    \
            std::ostringstream msg;                                                               \
            msg << "Error " << e << "(" << errName << ") " << __FILE__ << ":" << __LINE__ << ": " \
                << std::endl                                                                      \
                << #expr << std::endl                                                             \
                << errMsg << std::endl;                                                           \
            throw std::runtime_error(msg.str());                                                  \
        }                                                                                \
    } while(0)

#define HIP_CHECK_EXC_MESSAGE(expr, message)                                                      \
    do                                                                                \
    {                                                                                \
        hipError_t e = (expr);                                                                    \
        if(e)                                                                                \
        {                                                                                \
            const char*        errName = hipGetErrorName(e);                                      \
            const char*        errMsg  = hipGetErrorString(e);                                    \
            std::ostringstream msg;                                                               \
            msg << "Error " << e << "(" << errName << ") " << __FILE__ << ":" << __LINE__ << ": " \
                << std::endl                                                                      \
                << #expr << std::endl                                                             \
                << errMsg << std::endl                                                            \
                << (message) << std::endl;                                                        \
            throw std::runtime_error(msg.str());                                                  \
        }                                                                                \
    } while(0)

namespace Tensile
{
    namespace hip
    {
        template <typename T>
        void CopyTensor(T*                      dst,
                        T const*                src,
                        TensorDescriptor const& desc,
                        hipMemcpyKind           direction,
                        hipStream_t             stream = 0)
        {
            if(desc.dimensions() == 0 || desc.totalLogicalElements() == 0)
                return;

            auto const&         sizes   = desc.sizes();
            auto const&         strides = desc.strides();
            std::vector<size_t> coord(desc.dimensions(), 0);

            size_t contiguousDimensions = 0;
            size_t expectedStride       = 1;

            // Optimize the number of copy operations by coalescing all the
            // dimensions that are contiguous in memory.
            for(size_t i = 0; i < desc.dimensions(); i++)
            {
                if(strides[i] > expectedStride)
                    break;

                contiguousDimensions = i + 1;

                if(i < desc.dimensions() - 1)
                    expectedStride = strides[i] * sizes[i];
            }

            auto copyCount = CoordCount(sizes.begin() + contiguousDimensions, sizes.end());

            size_t maxStride
                = *std::max_element(strides.begin(), strides.begin() + contiguousDimensions);
            size_t copyBytes = maxStride * sizes.at(contiguousDimensions - 1) * sizeof(T);

            for(size_t idx = 0; idx < copyCount; idx++)
            {
                CoordNumbered(idx,
                              coord.begin() + contiguousDimensions,
                              coord.end(),
                              sizes.begin() + contiguousDimensions,
                              sizes.end());

                auto beginOffset = desc.index(coord);

                HIP_CHECK_EXC(hipMemcpyAsync(
                    dst + beginOffset, src + beginOffset, copyBytes, direction, stream));
            }
        }
    } // namespace hip
} // namespace Tensile
<|endoftext|>


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

Licensed to the OpenCOR team under one or more contributor license agreements.
See the NOTICE.txt file distributed with this work for additional information
regarding copyright ownership. The OpenCOR team licenses this file to you under
the Apache License, Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.

*******************************************************************************/

//==============================================================================
// RawView plugin
//==============================================================================

#include "corecliutils.h"
#include "filemanager.h"
#include "rawviewplugin.h"
#include "rawviewwidget.h"

//==============================================================================

#include <QMainWindow>
#include <QSettings>

//==============================================================================

namespace OpenCOR {
namespace RawView {

//==============================================================================

PLUGININFO_FUNC RawViewPluginInfo()
{
    Descriptions descriptions;

    descriptions.insert("en", QString::fromUtf8("a plugin to edit files using a text editor."));
    descriptions.insert("fr", QString::fromUtf8("une extension pour éditer des fichiers à l'aide d'un éditeur de texte."));

    return new PluginInfo(PluginInfo::Editing, true, false,
                          QStringList() << "CoreEditing",
                          descriptions);
}

//==============================================================================
// Editing interface
//==============================================================================

Editor::EditorWidget * RawViewPlugin::editor(const QString &pFileName) const
{
    // Return the requested editor

    return mViewWidget->editor(pFileName);
}

//==============================================================================

bool RawViewPlugin::isEditorUseable(const QString &pFileName) const
{
    Q_UNUSED(pFileName);

    // We don't handle this interface...

    return true;
}

//==============================================================================

bool RawViewPlugin::isEditorContentsModified(const QString &pFileName) const
{
    // Return whether the requested editor has been modified, which here is done
    // by comparing its contents to that of the given file

    Editor::EditorWidget *crtEditor = editor(pFileName);

    return crtEditor?
               Core::FileManager::instance()->isDifferent(pFileName, crtEditor->contents()):
               false;
}

//==============================================================================
// File handling interface
//==============================================================================

bool RawViewPlugin::saveFile(const QString &pOldFileName,
                             const QString &pNewFileName)
{
    // Save the given file

    Editor::EditorWidget *crtEditor = editor(pOldFileName);

    return crtEditor?
               Core::writeTextToFile(pNewFileName, crtEditor->contents()):
               false;
}

//==============================================================================

void RawViewPlugin::fileOpened(const QString &pFileName)
{
    Q_UNUSED(pFileName);

    // We don't handle this interface...
}

//==============================================================================

void RawViewPlugin::filePermissionsChanged(const QString &pFileName)
{
    Q_UNUSED(pFileName);

    // We don't handle this interface...
}

//==============================================================================

void RawViewPlugin::fileModified(const QString &pFileName)
{
    Q_UNUSED(pFileName);

    // We don't handle this interface...
}

//==============================================================================

void RawViewPlugin::fileReloaded(const QString &pFileName)
{
    // The given file has been reloaded, so let our view widget know about it

    mViewWidget->fileReloaded(pFileName);
}

//==============================================================================

void RawViewPlugin::fileRenamed(const QString &pOldFileName,
                                const QString &pNewFileName)
{
    // The given file has been renamed, so let our view widget know about it

    mViewWidget->fileRenamed(pOldFileName, pNewFileName);
}

//==============================================================================

void RawViewPlugin::fileSaved(const QString &pFileName)
{
    // The given file has been saved, but because it was done directly by
    // manipulating the file, we need to ask our file manager to reload it, so
    // that anyone that relies on an internal representation of the file (e.g.
    // the CellML Annotation view plugin) will get properly updated

    Core::FileManager::instance()->reload(pFileName);
}

//==============================================================================

void RawViewPlugin::fileClosed(const QString &pFileName)
{
    Q_UNUSED(pFileName);

    // We don't handle this interface...
}

//==============================================================================
// I18n interface
//==============================================================================

void RawViewPlugin::retranslateUi()
{
    // Retranslate our view widget

    mViewWidget->retranslateUi();
}

//==============================================================================
// Plugin interface
//==============================================================================

void RawViewPlugin::initializePlugin(QMainWindow *pMainWindow)
{
    // Create our raw view widget

    mViewWidget = new RawViewWidget(pMainWindow);

    // Hide our raw view widget since it may not initially be shown in our
    // central widget

    mViewWidget->setVisible(false);
}

//==============================================================================

void RawViewPlugin::finalizePlugin()
{
    // We don't handle this interface...
}

//==============================================================================

void RawViewPlugin::pluginsInitialized(const Plugins &pLoadedPlugins)
{
    Q_UNUSED(pLoadedPlugins);

    // We don't handle this interface...
}

//==============================================================================

void RawViewPlugin::loadSettings(QSettings *pSettings)
{
    // Retrieve our raw view widget settings

    pSettings->beginGroup(mViewWidget->objectName());
        mViewWidget->loadSettings(pSettings);
    pSettings->endGroup();
}

//==============================================================================

void RawViewPlugin::saveSettings(QSettings *pSettings) const
{
    // Keep track of our raw view widget settings

    pSettings->beginGroup(mViewWidget->objectName());
        mViewWidget->saveSettings(pSettings);
    pSettings->endGroup();
}

//==============================================================================

void RawViewPlugin::handleAction(const QUrl &pUrl)
{
    Q_UNUSED(pUrl);

    // We don't handle this interface...
}

//==============================================================================
// View interface
//==============================================================================

ViewInterface::Mode RawViewPlugin::viewMode() const
{
    // Return our mode

    return ViewInterface::Editing;
}

//==============================================================================

QStringList RawViewPlugin::viewMimeTypes() const
{
    // Return the MIME types we support, i.e. any in our case

    return QStringList();
}

//==============================================================================

bool RawViewPlugin::hasViewWidget(const QString &pFileName)
{
    // Return whether we have a view widget for the given CellML file

    return mViewWidget->contains(pFileName);
}

//==============================================================================

QWidget * RawViewPlugin::viewWidget(const QString &pFileName)
{
    // Update and return our raw view widget using the given file

    mViewWidget->initialize(pFileName);

    return mViewWidget;
}

//==============================================================================

void RawViewPlugin::removeViewWidget(const QString &pFileName)
{
    // Ask our raw view widget to finalise the given file

    mViewWidget->finalize(pFileName);
}

//==============================================================================

QString RawViewPlugin::viewName() const
{
    // Return our raw view's name

    return tr("Raw");
}

//==============================================================================

QIcon RawViewPlugin::fileTabIcon(const QString &pFileName) const
{
    Q_UNUSED(pFileName);

    // We don't handle this interface...

    return QIcon();
}

//==============================================================================

}   // namespace RawView
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<commit_msg>Some minor cleaning up [ci skip].<commit_after>/*******************************************************************************

Licensed to the OpenCOR team under one or more contributor license agreements.
See the NOTICE.txt file distributed with this work for additional information
regarding copyright ownership. The OpenCOR team licenses this file to you under
the Apache License, Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.

*******************************************************************************/

//==============================================================================
// RawView plugin
//==============================================================================

#include "corecliutils.h"
#include "filemanager.h"
#include "rawviewplugin.h"
#include "rawviewwidget.h"

//==============================================================================

#include <QMainWindow>
#include <QSettings>

//==============================================================================

namespace OpenCOR {
namespace RawView {

//==============================================================================

PLUGININFO_FUNC RawViewPluginInfo()
{
    Descriptions descriptions;

    descriptions.insert("en", QString::fromUtf8("a plugin to edit files using a text editor."));
    descriptions.insert("fr", QString::fromUtf8("une extension pour éditer des fichiers à l'aide d'un éditeur de texte."));

    return new PluginInfo(PluginInfo::Editing, true, false,
                          QStringList() << "CoreEditing",
                          descriptions);
}

//==============================================================================
// Editing interface
//==============================================================================

Editor::EditorWidget * RawViewPlugin::editor(const QString &pFileName) const
{
    // Return the requested editor

    return mViewWidget->editor(pFileName);
}

//==============================================================================

bool RawViewPlugin::isEditorUseable(const QString &pFileName) const
{
    Q_UNUSED(pFileName);

    // We don't handle this interface...

    return true;
}

//==============================================================================

bool RawViewPlugin::isEditorContentsModified(const QString &pFileName) const
{
    // Return whether the requested editor has been modified, which here is done
    // by comparing its contents to that of the given file

    Editor::EditorWidget *crtEditor = editor(pFileName);

    return crtEditor?
               Core::FileManager::instance()->isDifferent(pFileName, crtEditor->contents()):
               false;
}

//==============================================================================
// File handling interface
//==============================================================================

bool RawViewPlugin::saveFile(const QString &pOldFileName,
                             const QString &pNewFileName)
{
    // Save the given file

    Editor::EditorWidget *crtEditor = editor(pOldFileName);

    return crtEditor?
               Core::writeTextToFile(pNewFileName, crtEditor->contents()):
               false;
}

//==============================================================================

void RawViewPlugin::fileOpened(const QString &pFileName)
{
    Q_UNUSED(pFileName);

    // We don't handle this interface...
}

//==============================================================================

void RawViewPlugin::filePermissionsChanged(const QString &pFileName)
{
    Q_UNUSED(pFileName);

    // We don't handle this interface...
}

//==============================================================================

void RawViewPlugin::fileModified(const QString &pFileName)
{
    Q_UNUSED(pFileName);

    // We don't handle this interface...
}

//==============================================================================

void RawViewPlugin::fileReloaded(const QString &pFileName)
{
    // The given file has been reloaded, so let our view widget know about it

    mViewWidget->fileReloaded(pFileName);
}

//==============================================================================

void RawViewPlugin::fileRenamed(const QString &pOldFileName,
                                const QString &pNewFileName)
{
    // The given file has been renamed, so let our view widget know about it

    mViewWidget->fileRenamed(pOldFileName, pNewFileName);
}

//==============================================================================

void RawViewPlugin::fileSaved(const QString &pFileName)
{
    // The given file has been saved, but because it was done directly by
    // manipulating the file, we need to ask our file manager to reload it, so
    // that anyone that relies on an internal representation of the file (e.g.
    // the CellML Annotation view plugin) will get properly updated

    Core::FileManager::instance()->reload(pFileName);
}

//==============================================================================

void RawViewPlugin::fileClosed(const QString &pFileName)
{
    Q_UNUSED(pFileName);

    // We don't handle this interface...
}

//==============================================================================
// I18n interface
//==============================================================================

void RawViewPlugin::retranslateUi()
{
    // Retranslate our view widget

    mViewWidget->retranslateUi();
}

//==============================================================================
// Plugin interface
//==============================================================================

void RawViewPlugin::initializePlugin(QMainWindow *pMainWindow)
{
    // Create our raw view widget

    mViewWidget = new RawViewWidget(pMainWindow);

    // Hide our raw view widget since it may not initially be shown in our
    // central widget

    mViewWidget->setVisible(false);
}

//==============================================================================

void RawViewPlugin::finalizePlugin()
{
    // We don't handle this interface...
}

//==============================================================================

void RawViewPlugin::pluginsInitialized(const Plugins &pLoadedPlugins)
{
    Q_UNUSED(pLoadedPlugins);

    // We don't handle this interface...
}

//==============================================================================

void RawViewPlugin::loadSettings(QSettings *pSettings)
{
    // Retrieve our raw view widget settings

    pSettings->beginGroup(mViewWidget->objectName());
        mViewWidget->loadSettings(pSettings);
    pSettings->endGroup();
}

//==============================================================================

void RawViewPlugin::saveSettings(QSettings *pSettings) const
{
    // Keep track of our raw view widget settings

    pSettings->beginGroup(mViewWidget->objectName());
        mViewWidget->saveSettings(pSettings);
    pSettings->endGroup();
}

//==============================================================================

void RawViewPlugin::handleAction(const QUrl &pUrl)
{
    Q_UNUSED(pUrl);

    // We don't handle this interface...
}

//==============================================================================
// View interface
//==============================================================================

ViewInterface::Mode RawViewPlugin::viewMode() const
{
    // Return our mode

    return ViewInterface::Editing;
}

//==============================================================================

QStringList RawViewPlugin::viewMimeTypes() const
{
    // Return the MIME types we support, i.e. any in our case

    return QStringList();
}

//==============================================================================

bool RawViewPlugin::hasViewWidget(const QString &pFileName)
{
    // Return whether we have a view widget for the given file

    return mViewWidget->contains(pFileName);
}

//==============================================================================

QWidget * RawViewPlugin::viewWidget(const QString &pFileName)
{
    // Update and return our raw view widget using the given file

    mViewWidget->initialize(pFileName);

    return mViewWidget;
}

//==============================================================================

void RawViewPlugin::removeViewWidget(const QString &pFileName)
{
    // Ask our raw view widget to finalise the given file

    mViewWidget->finalize(pFileName);
}

//==============================================================================

QString RawViewPlugin::viewName() const
{
    // Return our raw view's name

    return tr("Raw");
}

//==============================================================================

QIcon RawViewPlugin::fileTabIcon(const QString &pFileName) const
{
    Q_UNUSED(pFileName);

    // We don't handle this interface...

    return QIcon();
}

//==============================================================================

}   // namespace RawView
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "src/protozero/filtering/filter_bytecode_parser.h"

#include "perfetto/base/logging.h"
#include "perfetto/ext/base/hash.h"
#include "perfetto/protozero/packed_repeated_fields.h"
#include "perfetto/protozero/proto_decoder.h"
#include "perfetto/protozero/proto_utils.h"
#include "src/protozero/filtering/filter_bytecode_common.h"

namespace protozero {

void FilterBytecodeParser::Reset() {
  bool suppress = suppress_logs_for_fuzzer_;
  *this = FilterBytecodeParser();
  suppress_logs_for_fuzzer_ = suppress;
}

bool FilterBytecodeParser::Load(const void* filter_data, size_t len) {
  Reset();
  bool res = LoadInternal(static_cast<const uint8_t*>(filter_data), len);
  // If load fails, don't leave the parser in a half broken state.
  if (!res)
    Reset();
  return res;
}

bool FilterBytecodeParser::LoadInternal(const uint8_t* bytecode_data,
                                        size_t len) {
  // First unpack the varints into a plain uint32 vector, so it's easy to
  // iterate through them and look ahead.
  std::vector<uint32_t> words;
  bool packed_parse_err = false;
  words.reserve(len);  // An overestimation, but avoids reallocations.
  using BytecodeDecoder =
      PackedRepeatedFieldIterator<proto_utils::ProtoWireType::kVarInt,
                                  uint32_t>;
  for (BytecodeDecoder it(bytecode_data, len, &packed_parse_err); it; ++it)
    words.emplace_back(*it);

  if (packed_parse_err || words.empty())
    return false;

  perfetto::base::Hash hasher;
  for (size_t i = 0; i < words.size() - 1; ++i)
    hasher.Update(words[i]);

  uint32_t expected_csum = static_cast<uint32_t>(hasher.digest());
  if (expected_csum != words.back()) {
    if (!suppress_logs_for_fuzzer_) {
      PERFETTO_ELOG("Filter bytecode checksum failed. Expected: %x, actual: %x",
                    expected_csum, words.back());
    }
    return false;
  }

  words.pop_back();  // Pop the checksum.

  // Temporay storage for each message. Cleared on every END_OF_MESSAGE.
  std::vector<uint32_t> direct_indexed_fields;
  std::vector<uint32_t> ranges;
  uint32_t max_msg_index = 0;

  auto add_directly_indexed_field = [&](uint32_t field_id, uint32_t msg_id) {
    PERFETTO_DCHECK(field_id > 0 && field_id < kDirectlyIndexLimit);
    direct_indexed_fields.resize(std::max(direct_indexed_fields.size(),
                                          static_cast<size_t>(field_id) + 1));
    direct_indexed_fields[field_id] = kAllowed | msg_id;
  };

  auto add_range = [&](uint32_t id_start, uint32_t id_end, uint32_t msg_id) {
    PERFETTO_DCHECK(id_end > id_start);
    PERFETTO_DCHECK(id_start >= kDirectlyIndexLimit);
    ranges.emplace_back(id_start);
    ranges.emplace_back(id_end);
    ranges.emplace_back(kAllowed | msg_id);
  };

  for (size_t i = 0; i < words.size(); ++i) {
    const uint32_t word = words[i];
    const bool has_next_word = i < words.size() - 1;
    const uint32_t opcode = word & 0x7u;
    const uint32_t field_id = word >> 3;

    if (field_id == 0 && opcode != kFilterOpcode_EndOfMessage) {
      PERFETTO_DLOG("bytecode error @ word %zu, invalid field id (0)", i);
      return false;
    }

    if (opcode == kFilterOpcode_SimpleField ||
        opcode == kFilterOpcode_NestedField) {
      // Field words are organized as follow:
      // MSB: 1 if allowed, 0 if not allowed.
      // Remaining bits:
      //   Message index in the case of nested (non-simple) messages.
      //   0x7f..f in the case of simple messages.
      uint32_t msg_id;
      if (opcode == kFilterOpcode_SimpleField) {
        msg_id = kSimpleField;
      } else {  // FILTER_OPCODE_NESTED_FIELD
        // The next word in the bytecode contains the message index.
        if (!has_next_word) {
          PERFETTO_DLOG("bytecode error @ word %zu: unterminated nested field",
                        i);
          return false;
        }
        msg_id = words[++i];
        max_msg_index = std::max(max_msg_index, msg_id);
      }

      if (field_id < kDirectlyIndexLimit) {
        add_directly_indexed_field(field_id, msg_id);
      } else {
        // In the case of a large field id (rare) we waste an extra word and
        // represent it as a range. Doesn't make sense to introduce extra
        // complexity to deal with rare cases like this.
        add_range(field_id, field_id + 1, msg_id);
      }
    } else if (opcode == kFilterOpcode_SimpleFieldRange) {
      if (!has_next_word) {
        PERFETTO_DLOG("bytecode error @ word %zu: unterminated range", i);
        return false;
      }
      const uint32_t range_len = words[++i];
      const uint32_t range_end = field_id + range_len;  // STL-style, excl.
      uint32_t id = field_id;

      // Here's the subtle complexity: at the bytecode level, we don't know
      // anything about the kDirectlyIndexLimit. It is legit to define a range
      // that spans across the direct-indexing threshold (e.g. 126-132). In that
      // case we want to add all the elements < the indexing to the O(1) bucket
      // and add only the remaining range as a non-indexed range.
      for (; id < range_end && id < kDirectlyIndexLimit; ++id)
        add_directly_indexed_field(id, kAllowed | kSimpleField);
      PERFETTO_DCHECK(id >= kDirectlyIndexLimit || id == range_end);
      if (id < range_end)
        add_range(id, range_end, kSimpleField);
    } else if (opcode == kFilterOpcode_EndOfMessage) {
      // For each message append:
      // 1. The "header" word telling how many directly indexed fields there
      //    are.
      // 2. The words for the directly indexed fields (id < 128).
      // 3. The rest of the fields, encoded as ranges.
      // Also update the |message_offset_| index to remember the word offset for
      // the current message.
      message_offset_.emplace_back(static_cast<uint32_t>(words_.size()));
      words_.emplace_back(static_cast<uint32_t>(direct_indexed_fields.size()));
      words_.insert(words_.end(), direct_indexed_fields.begin(),
                    direct_indexed_fields.end());
      words_.insert(words_.end(), ranges.begin(), ranges.end());
      direct_indexed_fields.clear();
      ranges.clear();
    } else {
      PERFETTO_DLOG("bytecode error @ word %zu: invalid opcode (%x)", i, word);
      return false;
    }
  }  // (for word in bytecode).

  if (max_msg_index > 0 && max_msg_index >= message_offset_.size()) {
    PERFETTO_DLOG(
        "bytecode error: a message index (%u) is out of range "
        "(num_messages=%zu)",
        max_msg_index, message_offset_.size());
    return false;
  }

  // Add a final entry to |message_offset_| so we can tell where the last
  // message ends without an extra branch in the Query() hotpath.
  message_offset_.emplace_back(static_cast<uint32_t>(words_.size()));

  return true;
}

FilterBytecodeParser::QueryResult FilterBytecodeParser::Query(
    uint32_t msg_index,
    uint32_t field_id) {
  FilterBytecodeParser::QueryResult res{false, 0u};
  if (static_cast<uint64_t>(msg_index) + 1 >=
      static_cast<uint64_t>(message_offset_.size())) {
    return res;
  }
  const uint32_t start_offset = message_offset_[msg_index];
  // These are DCHECKs and not just CHECKS because the |words_| is populated
  // by the LoadInternal call above. These cannot be violated with a malformed
  // bytecode.
  PERFETTO_DCHECK(start_offset < words_.size());
  const uint32_t* word = &words_[start_offset];
  const uint32_t* const end = &words_[message_offset_[msg_index + 1]];
  PERFETTO_DCHECK(end > word && end <= words_.data() + words_.size());
  const uint32_t num_directly_indexed = *(word++);
  PERFETTO_DCHECK(num_directly_indexed <= kDirectlyIndexLimit);
  PERFETTO_DCHECK(word + num_directly_indexed <= end);
  uint32_t field_state = 0;
  if (PERFETTO_LIKELY(field_id < num_directly_indexed)) {
    PERFETTO_DCHECK(&word[field_id] < end);
    field_state = word[field_id];
  } else {
    for (word = word + num_directly_indexed; word + 2 < end;) {
      const uint32_t range_start = *(word++);
      const uint32_t range_end = *(word++);
      const uint32_t range_state = *(word++);
      if (field_id >= range_start && field_id < range_end) {
        field_state = range_state;
        break;
      }
    }  // for (word in ranges)
  }    // if (field_id >= num_directly_indexed)

  res.allowed = (field_state & kAllowed) != 0;
  res.nested_msg_index = field_state & ~kAllowed;
  PERFETTO_DCHECK(res.simple_field() ||
                  res.nested_msg_index < message_offset_.size() - 1);
  return res;
}

}  // namespace protozero
<commit_msg>trace filtering: avoid dereferencing vector[end]<commit_after>/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "src/protozero/filtering/filter_bytecode_parser.h"

#include "perfetto/base/logging.h"
#include "perfetto/ext/base/hash.h"
#include "perfetto/protozero/packed_repeated_fields.h"
#include "perfetto/protozero/proto_decoder.h"
#include "perfetto/protozero/proto_utils.h"
#include "src/protozero/filtering/filter_bytecode_common.h"

namespace protozero {

void FilterBytecodeParser::Reset() {
  bool suppress = suppress_logs_for_fuzzer_;
  *this = FilterBytecodeParser();
  suppress_logs_for_fuzzer_ = suppress;
}

bool FilterBytecodeParser::Load(const void* filter_data, size_t len) {
  Reset();
  bool res = LoadInternal(static_cast<const uint8_t*>(filter_data), len);
  // If load fails, don't leave the parser in a half broken state.
  if (!res)
    Reset();
  return res;
}

bool FilterBytecodeParser::LoadInternal(const uint8_t* bytecode_data,
                                        size_t len) {
  // First unpack the varints into a plain uint32 vector, so it's easy to
  // iterate through them and look ahead.
  std::vector<uint32_t> words;
  bool packed_parse_err = false;
  words.reserve(len);  // An overestimation, but avoids reallocations.
  using BytecodeDecoder =
      PackedRepeatedFieldIterator<proto_utils::ProtoWireType::kVarInt,
                                  uint32_t>;
  for (BytecodeDecoder it(bytecode_data, len, &packed_parse_err); it; ++it)
    words.emplace_back(*it);

  if (packed_parse_err || words.empty())
    return false;

  perfetto::base::Hash hasher;
  for (size_t i = 0; i < words.size() - 1; ++i)
    hasher.Update(words[i]);

  uint32_t expected_csum = static_cast<uint32_t>(hasher.digest());
  if (expected_csum != words.back()) {
    if (!suppress_logs_for_fuzzer_) {
      PERFETTO_ELOG("Filter bytecode checksum failed. Expected: %x, actual: %x",
                    expected_csum, words.back());
    }
    return false;
  }

  words.pop_back();  // Pop the checksum.

  // Temporay storage for each message. Cleared on every END_OF_MESSAGE.
  std::vector<uint32_t> direct_indexed_fields;
  std::vector<uint32_t> ranges;
  uint32_t max_msg_index = 0;

  auto add_directly_indexed_field = [&](uint32_t field_id, uint32_t msg_id) {
    PERFETTO_DCHECK(field_id > 0 && field_id < kDirectlyIndexLimit);
    direct_indexed_fields.resize(std::max(direct_indexed_fields.size(),
                                          static_cast<size_t>(field_id) + 1));
    direct_indexed_fields[field_id] = kAllowed | msg_id;
  };

  auto add_range = [&](uint32_t id_start, uint32_t id_end, uint32_t msg_id) {
    PERFETTO_DCHECK(id_end > id_start);
    PERFETTO_DCHECK(id_start >= kDirectlyIndexLimit);
    ranges.emplace_back(id_start);
    ranges.emplace_back(id_end);
    ranges.emplace_back(kAllowed | msg_id);
  };

  for (size_t i = 0; i < words.size(); ++i) {
    const uint32_t word = words[i];
    const bool has_next_word = i < words.size() - 1;
    const uint32_t opcode = word & 0x7u;
    const uint32_t field_id = word >> 3;

    if (field_id == 0 && opcode != kFilterOpcode_EndOfMessage) {
      PERFETTO_DLOG("bytecode error @ word %zu, invalid field id (0)", i);
      return false;
    }

    if (opcode == kFilterOpcode_SimpleField ||
        opcode == kFilterOpcode_NestedField) {
      // Field words are organized as follow:
      // MSB: 1 if allowed, 0 if not allowed.
      // Remaining bits:
      //   Message index in the case of nested (non-simple) messages.
      //   0x7f..f in the case of simple messages.
      uint32_t msg_id;
      if (opcode == kFilterOpcode_SimpleField) {
        msg_id = kSimpleField;
      } else {  // FILTER_OPCODE_NESTED_FIELD
        // The next word in the bytecode contains the message index.
        if (!has_next_word) {
          PERFETTO_DLOG("bytecode error @ word %zu: unterminated nested field",
                        i);
          return false;
        }
        msg_id = words[++i];
        max_msg_index = std::max(max_msg_index, msg_id);
      }

      if (field_id < kDirectlyIndexLimit) {
        add_directly_indexed_field(field_id, msg_id);
      } else {
        // In the case of a large field id (rare) we waste an extra word and
        // represent it as a range. Doesn't make sense to introduce extra
        // complexity to deal with rare cases like this.
        add_range(field_id, field_id + 1, msg_id);
      }
    } else if (opcode == kFilterOpcode_SimpleFieldRange) {
      if (!has_next_word) {
        PERFETTO_DLOG("bytecode error @ word %zu: unterminated range", i);
        return false;
      }
      const uint32_t range_len = words[++i];
      const uint32_t range_end = field_id + range_len;  // STL-style, excl.
      uint32_t id = field_id;

      // Here's the subtle complexity: at the bytecode level, we don't know
      // anything about the kDirectlyIndexLimit. It is legit to define a range
      // that spans across the direct-indexing threshold (e.g. 126-132). In that
      // case we want to add all the elements < the indexing to the O(1) bucket
      // and add only the remaining range as a non-indexed range.
      for (; id < range_end && id < kDirectlyIndexLimit; ++id)
        add_directly_indexed_field(id, kAllowed | kSimpleField);
      PERFETTO_DCHECK(id >= kDirectlyIndexLimit || id == range_end);
      if (id < range_end)
        add_range(id, range_end, kSimpleField);
    } else if (opcode == kFilterOpcode_EndOfMessage) {
      // For each message append:
      // 1. The "header" word telling how many directly indexed fields there
      //    are.
      // 2. The words for the directly indexed fields (id < 128).
      // 3. The rest of the fields, encoded as ranges.
      // Also update the |message_offset_| index to remember the word offset for
      // the current message.
      message_offset_.emplace_back(static_cast<uint32_t>(words_.size()));
      words_.emplace_back(static_cast<uint32_t>(direct_indexed_fields.size()));
      words_.insert(words_.end(), direct_indexed_fields.begin(),
                    direct_indexed_fields.end());
      words_.insert(words_.end(), ranges.begin(), ranges.end());
      direct_indexed_fields.clear();
      ranges.clear();
    } else {
      PERFETTO_DLOG("bytecode error @ word %zu: invalid opcode (%x)", i, word);
      return false;
    }
  }  // (for word in bytecode).

  if (max_msg_index > 0 && max_msg_index >= message_offset_.size()) {
    PERFETTO_DLOG(
        "bytecode error: a message index (%u) is out of range "
        "(num_messages=%zu)",
        max_msg_index, message_offset_.size());
    return false;
  }

  // Add a final entry to |message_offset_| so we can tell where the last
  // message ends without an extra branch in the Query() hotpath.
  message_offset_.emplace_back(static_cast<uint32_t>(words_.size()));

  return true;
}

FilterBytecodeParser::QueryResult FilterBytecodeParser::Query(
    uint32_t msg_index,
    uint32_t field_id) {
  FilterBytecodeParser::QueryResult res{false, 0u};
  if (static_cast<uint64_t>(msg_index) + 1 >=
      static_cast<uint64_t>(message_offset_.size())) {
    return res;
  }
  const uint32_t start_offset = message_offset_[msg_index];
  // These are DCHECKs and not just CHECKS because the |words_| is populated
  // by the LoadInternal call above. These cannot be violated with a malformed
  // bytecode.
  PERFETTO_DCHECK(start_offset < words_.size());
  const uint32_t* word = &words_[start_offset];
  const uint32_t end_off = message_offset_[msg_index + 1];
  const uint32_t* const end = words_.data() + end_off;
  PERFETTO_DCHECK(end > word && end <= words_.data() + words_.size());
  const uint32_t num_directly_indexed = *(word++);
  PERFETTO_DCHECK(num_directly_indexed <= kDirectlyIndexLimit);
  PERFETTO_DCHECK(word + num_directly_indexed <= end);
  uint32_t field_state = 0;
  if (PERFETTO_LIKELY(field_id < num_directly_indexed)) {
    PERFETTO_DCHECK(&word[field_id] < end);
    field_state = word[field_id];
  } else {
    for (word = word + num_directly_indexed; word + 2 < end;) {
      const uint32_t range_start = *(word++);
      const uint32_t range_end = *(word++);
      const uint32_t range_state = *(word++);
      if (field_id >= range_start && field_id < range_end) {
        field_state = range_state;
        break;
      }
    }  // for (word in ranges)
  }    // if (field_id >= num_directly_indexed)

  res.allowed = (field_state & kAllowed) != 0;
  res.nested_msg_index = field_state & ~kAllowed;
  PERFETTO_DCHECK(res.simple_field() ||
                  res.nested_msg_index < message_offset_.size() - 1);
  return res;
}

}  // namespace protozero
<|endoftext|>


<commit_before>#include "waitForTouchSensorBlockGenerator.h"
#include "generatorBase/generatorCustomizer.h"

using namespace generatorBase::simple;
using namespace qReal;

WaitForTouchSensorBlockGenerator::WaitForTouchSensorBlockGenerator(const qrRepo::RepoApi &repo
		, GeneratorCustomizer &customizer
		, const Id &id
		, QObject *parent)
	: BindingGenerator(repo, customizer, id, "wait/touch.t", QList<Binding *>()
			<< Binding::createConverting("@@PORT@@", "Port", customizer.factory()->portNameConverter())
			<< Binding::createConverting("@@SIGN@@", "Sign", customizer.factory()->inequalitySignConverter())
			, parent)
{
}
<commit_msg>Fixed wrong template binding to Sign property in NXT WaitForTouchSensor block generator<commit_after>#include "waitForTouchSensorBlockGenerator.h"
#include "generatorBase/generatorCustomizer.h"

using namespace generatorBase::simple;
using namespace qReal;

WaitForTouchSensorBlockGenerator::WaitForTouchSensorBlockGenerator(const qrRepo::RepoApi &repo
		, GeneratorCustomizer &customizer
		, const Id &id
		, QObject *parent)
	: BindingGenerator(repo, customizer, id, "wait/touch.t", QList<Binding *>()
			<< Binding::createConverting("@@PORT@@", "Port", customizer.factory()->portNameConverter())
			, parent)
{
}
<|endoftext|>


<commit_before>#include <robocup2Dsim/engine/inventory.hpp>
#include <robocup2Dsim/engine/inventory.hxx>
#include <gtest/gtest.h>

namespace ren = robocup2Dsim::engine;

TEST(inventory_test, make_energy_basic)
{
    ren::energy value1{100U};
    auto array1 = ren::make_energy<4U>(value1);
    EXPECT_EQ(4U, array1->size())
	    << "make_energy did not create an array of the correct length";
    EXPECT_EQ(4U, std::count(array1->cbegin(), array1->cend(), value1))
	    << "make_energy did not initialise the array wit the correct value";
}

TEST(inventory_test, accrue_invalid)
{
    ren::energy value1{100U};
    auto stock1 = ren::make_energy<4U>(value1);
    ren::inventory_policy policy1{0U, 100U};
    ren::inventory inventory1(policy1);
    std::array<ren::energy, 4U> amount1{1U, 2U, 5U, 10U};
    auto result1 = inventory1.accrue(*stock1, amount1);
    for (const ren::inventory::accrue_result result: result1)
    {
	EXPECT_EQ(ren::inventory::accrue_result::oversupply, result) << "Accruing to a full inventory succeeded";
    }
}

TEST(inventory_test, spend_invalid)
{
    ren::energy value1{0U};
    auto stock1 = ren::make_energy<4U>(value1);
    ren::inventory_policy policy1{0U, 100U};
    ren::inventory inventory1(policy1);
    std::array<ren::energy, 4U> amount1{1U, 2U, 5U, 10U};
    auto result1 = inventory1.spend(*stock1, amount1);
    for (const ren::inventory::spend_result result: result1)
    {
	EXPECT_EQ(ren::inventory::spend_result::understock, result) << "Spending an empty inventory succeeded";
    }
}
<commit_msg>adding more test cases<commit_after>#include <robocup2Dsim/engine/inventory.hpp>
#include <robocup2Dsim/engine/inventory.hxx>
#include <gtest/gtest.h>
#include <limits>

namespace ren = robocup2Dsim::engine;

TEST(inventory_test, make_energy_basic)
{
    ren::energy value1{100U};
    auto array1 = ren::make_energy<4U>(value1);
    EXPECT_EQ(4U, array1->size())
	    << "make_energy did not create an array of the correct length";
    EXPECT_EQ(4U, std::count(array1->cbegin(), array1->cend(), value1))
	    << "make_energy did not initialise the array wit the correct value";
}

TEST(inventory_test, accrue_invalid)
{
    ren::energy value1{100U};
    auto stock1 = ren::make_energy<4U>(value1);
    ren::inventory_policy policy1{0U, 100U};
    ren::inventory inventory1(policy1);
    std::array<ren::energy, 4U> amount1{1U, 2U, 5U, 10U};
    auto result1 = inventory1.accrue(*stock1, amount1);
    for (const ren::inventory::accrue_result result: result1)
    {
	EXPECT_EQ(ren::inventory::accrue_result::oversupply, result) << "Accruing to a full inventory succeeded";
    }

    ren::energy value2{50U};
    auto stock2 = ren::make_energy<4U>(value2);
    ren::inventory_policy policy2{0U, 100U};
    ren::inventory inventory2(policy2);
    std::array<ren::energy, 4U> amount2{100U, 20U, 5U, 51U};
    auto result2 = inventory2.accrue(*stock2, amount2);
    EXPECT_EQ(ren::inventory::accrue_result::oversupply, result2[0]) << "Accruing over the maximum succeeded";
    EXPECT_EQ(ren::inventory::accrue_result::success, result2[1]) << "Accruing below the maximum failed";
    EXPECT_EQ(ren::inventory::accrue_result::success, result2[2]) << "Accruing below the maximum failed";
    EXPECT_EQ(ren::inventory::accrue_result::oversupply, result2[3]) << "Accruing over the maximum succeeded";
}

TEST(inventory_test, accrue_overflow)
{
    ren::energy value1{std::numeric_limits<decltype(ren::energy::quantity)>::max()};
    auto stock1 = ren::make_energy<4U>(value1);
    ren::inventory_policy policy1{0U, std::numeric_limits<decltype(ren::energy::quantity)>::max()};
    ren::inventory inventory1(policy1);
    std::array<ren::energy, 4U> amount1{1U, 2U, 5U, 10U};
    auto result1 = inventory1.accrue(*stock1, amount1);
    for (const ren::inventory::accrue_result result: result1)
    {
	EXPECT_EQ(ren::inventory::accrue_result::oversupply, result) << "Accruing to a full inventory succeeded";
    }
}

TEST(inventory_test, accrue_basic)
{
    ren::energy value1{90U};
    auto stock1 = ren::make_energy<4U>(value1);
    ren::inventory_policy policy1{0U, 100U};
    ren::inventory inventory1(policy1);
    std::array<ren::energy, 4U> amount1{1U, 2U, 5U, 10U};
    auto result1 = inventory1.accrue(*stock1, amount1);
    for (const ren::inventory::accrue_result result: result1)
    {
	EXPECT_EQ(ren::inventory::accrue_result::success, result) << "Accruing under the maximum failed";
    }
    EXPECT_EQ(90U + 1U, (*stock1)[0].quantity) << "Accruing with specified amount failed";
    EXPECT_EQ(90U + 2U, (*stock1)[1].quantity) << "Accruing with specified amount failed";
    EXPECT_EQ(90U + 5U, (*stock1)[2].quantity) << "Accruing with specified amount failed";
    EXPECT_EQ(90U + 10U, (*stock1)[3].quantity) << "Accruing with specified amount failed";

    std::array<ren::energy, 4U> stock2{90U, 40U, 0U, 80U};
    ren::inventory_policy policy2{0U, 100U};
    ren::inventory inventory2(policy2);
    std::array<ren::energy, 4U> amount2{10U, 10U, 10U, 10U};
    auto result2 = inventory2.accrue(stock2, amount2);
    for (const ren::inventory::accrue_result result: result2)
    {
	EXPECT_EQ(ren::inventory::accrue_result::success, result) << "Accruing under the maximum failed";
    }
    EXPECT_EQ(90U + 10U, stock2[0].quantity) << "Accruing with specified amount failed";
    EXPECT_EQ(40U + 10U, stock2[1].quantity) << "Accruing with specified amount failed";
    EXPECT_EQ(0U + 10U, stock2[2].quantity) << "Accruing with specified amount failed";
    EXPECT_EQ(80U + 10U, stock2[3].quantity) << "Accruing with specified amount failed";
}

TEST(inventory_test, spend_invalid)
{
    ren::energy value1{0U};
    auto stock1 = ren::make_energy<4U>(value1);
    ren::inventory_policy policy1{0U, 100U};
    ren::inventory inventory1(policy1);
    std::array<ren::energy, 4U> amount1{1U, 2U, 5U, 10U};
    auto result1 = inventory1.spend(*stock1, amount1);
    for (const ren::inventory::spend_result result: result1)
    {
	EXPECT_EQ(ren::inventory::spend_result::understock, result) << "Spending an empty inventory succeeded";
    }

    ren::energy value2{10U};
    auto stock2 = ren::make_energy<4U>(value2);
    ren::inventory_policy policy2{0U, 100U};
    ren::inventory inventory2(policy2);
    std::array<ren::energy, 4U> amount2{11U, 2U, 5U, 40U};
    auto result2 = inventory2.spend(*stock2, amount2);
    EXPECT_EQ(ren::inventory::spend_result::understock, result2[0]) << "Spending under the minumum succeeded";
    EXPECT_EQ(ren::inventory::spend_result::success, result2[1]) << "Spending above the minimum failed";
    EXPECT_EQ(ren::inventory::spend_result::success, result2[2]) << "Spending above the minimum failed";
    EXPECT_EQ(ren::inventory::spend_result::understock, result2[3]) << "Spending under the minimum succeeded";
}

TEST(inventory_test, spend_underflow)
{
    ren::energy value1{std::numeric_limits<decltype(ren::energy::quantity)>::min()};
    auto stock1 = ren::make_energy<4U>(value1);
    ren::inventory_policy policy1{std::numeric_limits<decltype(ren::energy::quantity)>::min(), 100U};
    ren::inventory inventory1(policy1);
    std::array<ren::energy, 4U> amount1{1U, 2U, 5U, 10U};
    auto result1 = inventory1.spend(*stock1, amount1);
    for (const ren::inventory::spend_result result: result1)
    {
	EXPECT_EQ(ren::inventory::spend_result::understock, result) << "Spending an empty inventory succeeded";
    }
}

TEST(inventory_test, spend_basic)
{
    ren::energy value1{20U};
    auto stock1 = ren::make_energy<4U>(value1);
    ren::inventory_policy policy1{0U, 100U};
    ren::inventory inventory1(policy1);
    std::array<ren::energy, 4U> amount1{1U, 8U, 15U, 20U};
    auto result1 = inventory1.spend(*stock1, amount1);
    for (const ren::inventory::spend_result result: result1)
    {
	EXPECT_EQ(ren::inventory::spend_result::success, result) << "Spending above the minimum failed";
    }
    EXPECT_EQ(20U - 1U, (*stock1)[0].quantity) << "Spending with specified amount failed";
    EXPECT_EQ(20U - 8U, (*stock1)[1].quantity) << "Spending with specified amount failed";
    EXPECT_EQ(20U - 15U, (*stock1)[2].quantity) << "Spending with specified amount failed";
    EXPECT_EQ(20U - 20U, (*stock1)[3].quantity) << "Spending with specified amount failed";

    std::array<ren::energy, 4U> stock2{10U, 0U, 20U, 0U};
    ren::inventory_policy policy2{0U, 100U};
    ren::inventory inventory2(policy2);
    std::array<ren::energy, 4U> amount2{10U, 0U, 20U, 0U};
    auto result2 = inventory2.spend(stock2, amount2);
    for (const ren::inventory::spend_result result: result2)
    {
	EXPECT_EQ(ren::inventory::spend_result::success, result) << "Spending under the minimum failed";
    }
    EXPECT_EQ(10U - 10U, stock2[0].quantity) << "Spending with specified amount failed";
    EXPECT_EQ(0U - 0U, stock2[1].quantity) << "Spending with specified amount failed";
    EXPECT_EQ(20U - 20U, stock2[2].quantity) << "Spending with specified amount failed";
    EXPECT_EQ(0U - 0U, stock2[3].quantity) << "Spending with specified amount failed";
}
<|endoftext|>