<commit_before>/*
Copyright (c) 2003-2010 Sony Pictures Imageworks Inc., et al.
All Rights Reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
  notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
  notice, this list of conditions and the following disclaimer in the
  documentation and/or other materials provided with the distribution.
* Neither the name of Sony Pictures Imageworks nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <OpenColorIO/OpenColorIO.h>

OCIO_NAMESPACE_ENTER
{

    Exception::Exception(const char * msg) throw()
    : std::runtime_error(msg)
    {}

    Exception::Exception(const Exception& e) throw()
    : std::runtime_error(e)
    {}

    //*** ~Exception
    Exception::~Exception() throw()
    {
    }

    ExceptionMissingFile::ExceptionMissingFile(const char * msg) throw()
    : Exception(msg)
    {}

    ExceptionMissingFile::ExceptionMissingFile(const ExceptionMissingFile& e) throw()
    : Exception(e)
    {}

}
OCIO_NAMESPACE_EXIT

///////////////////////////////////////////////////////////////////////////////

#ifdef OCIO_UNIT_TEST

namespace OCIO = OCIO_NAMESPACE;
#include "UnitTest.h"

OIIO_ADD_TEST(Exception, Basic)
{
    static const char* dummyErrorStr = "Dummy error";

    // Test 1

    try
    {
        throw OCIO::Exception(dummyErrorStr);
    }
    catch(const std::exception& ex)
    {
        OIIO_CHECK_EQUAL(strcmp(ex.what(), dummyErrorStr), 0);
    }
    catch(...)
    {
        OIIO_CHECK_EQUAL(0x0, "wrong exception type");
    }

    // Test 2

    try
    {
        OCIO::Exception ex(dummyErrorStr);
        throw OCIO::Exception(ex);
    }
    catch(const std::exception& ex)
    {
        OIIO_CHECK_EQUAL(strcmp(ex.what(), dummyErrorStr), 0);
    }
    catch(...)
    {
        OIIO_CHECK_EQUAL(0x0, "wrong exception type");
    }
}

#endif // OCIO_UNIT_TEST
<commit_msg>Remove the stl string of Exception from the public API, fix *nix build break, part II<commit_after>/*
Copyright (c) 2003-2010 Sony Pictures Imageworks Inc., et al.
All Rights Reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
  notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
  notice, this list of conditions and the following disclaimer in the
  documentation and/or other materials provided with the distribution.
* Neither the name of Sony Pictures Imageworks nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <OpenColorIO/OpenColorIO.h>

OCIO_NAMESPACE_ENTER
{

    Exception::Exception(const char * msg) throw()
    : std::runtime_error(msg)
    {}

    Exception::Exception(const Exception& e) throw()
    : std::runtime_error(e)
    {}

    //*** ~Exception
    Exception::~Exception() throw()
    {
    }

    ExceptionMissingFile::ExceptionMissingFile(const char * msg) throw()
    : Exception(msg)
    {}

    ExceptionMissingFile::ExceptionMissingFile(const ExceptionMissingFile& e) throw()
    : Exception(e)
    {}

}
OCIO_NAMESPACE_EXIT

///////////////////////////////////////////////////////////////////////////////

#ifdef OCIO_UNIT_TEST

namespace OCIO = OCIO_NAMESPACE;
#include "UnitTest.h"

#include <string.h>

OIIO_ADD_TEST(Exception, Basic)
{
    static const char* dummyErrorStr = "Dummy error";

    // Test 1

    try
    {
        throw OCIO::Exception(dummyErrorStr);
    }
    catch(const std::exception& ex)
    {
        OIIO_CHECK_EQUAL(strcmp(ex.what(), dummyErrorStr), 0);
    }
    catch(...)
    {
        OIIO_CHECK_EQUAL(0x0, "wrong exception type");
    }

    // Test 2

    try
    {
        OCIO::Exception ex(dummyErrorStr);
        throw OCIO::Exception(ex);
    }
    catch(const std::exception& ex)
    {
        OIIO_CHECK_EQUAL(strcmp(ex.what(), dummyErrorStr), 0);
    }
    catch(...)
    {
        OIIO_CHECK_EQUAL(0x0, "wrong exception type");
    }
}

#endif // OCIO_UNIT_TEST
<|endoftext|>


<commit_before>#include "fmv.hpp"
#include "imgui/imgui.h"
#include "core/audiobuffer.hpp"
#include "gamedata.hpp"

#ifdef _WIN32
#include <windows.h>
#endif
#ifdef __APPLE__
#  include <OpenGL/gl.h>
#else
#  include <GL/gl.h>
#endif/*__APPLE__*/

class FmvUi
{
private:
    char buf[4096];
    ImGuiTextFilter mFilter;
    int listbox_item_current = 1;
    std::vector<const char*> listbox_items;
public:
    FmvUi()
    {
#ifdef _WIN32
        strcpy(buf, "C:\\Program Files (x86)\\Steam\\SteamApps\\common\\Oddworld Abes Oddysee\\");
#else
        strcpy(buf, "/home/paul/ae_test/");
#endif
    }

    void DrawVideoSelectionUi(std::unique_ptr<Oddlib::Masher>& video, FILE*& fp, SDL_Surface*& videoFrame, const std::string& setName, const std::vector<std::string>& allFmvs)
    {
        std::string name = "Video player (" + setName + ")";
        ImGui::Begin(name.c_str(), nullptr, ImVec2(550, 580), 1.0f, ImGuiWindowFlags_NoCollapse);

        ImGui::InputText("Video path", buf, sizeof(buf));

        mFilter.Draw();

        listbox_items.resize(allFmvs.size());

        int matchingFilter = 0;
        for (size_t i = 0; i < allFmvs.size(); i++)
        {
            if (mFilter.PassFilter(allFmvs[i].c_str()))
            {
                listbox_items[matchingFilter] = allFmvs[i].c_str();
                matchingFilter++;
            }
        }
        ImGui::PushItemWidth(-1);
        ImGui::ListBox("##", &listbox_item_current, listbox_items.data(), matchingFilter, 27);

        if (ImGui::Button("Play", ImVec2(ImGui::GetWindowWidth(), 20)))
        {
            std::string fullPath = std::string(buf) + listbox_items[listbox_item_current];
            std::cout << "Play " << listbox_items[listbox_item_current] << std::endl;
            try
            {
                video = std::make_unique<Oddlib::Masher>(fullPath);
                if (videoFrame)
                {
                    SDL_FreeSurface(videoFrame);
                    videoFrame = nullptr;
                }

                if (video->HasAudio())
                {
                    AudioBuffer::ChangeAudioSpec(video->SingleAudioFrameSizeBytes(), video->AudioSampleRate());
                }

                if (video->HasVideo())
                {
                    videoFrame = SDL_CreateRGBSurface(0, video->Width(), video->Height(), 32, 0, 0, 0, 0);
                    //                    targetFps = video->FrameRate() * 2;
                }

                SDL_ShowCursor(0);
            }
            catch (const Oddlib::Exception& ex)
            {
                // ImGui::Text(ex.what());

                fp = fopen(fullPath.c_str(), "rb");
                AudioBuffer::ChangeAudioSpec(8064/4, 37800);

            }
        }

        ImGui::End();
    }
};

struct CDXASector
{
    /*
    uint8_t sync[12];
    uint8_t header[4];

    struct CDXASubHeader
    {
        uint8_t file_number;
        uint8_t channel;
        uint8_t submode;
        uint8_t coding_info;
        uint8_t file_number_copy;
        uint8_t channel_number_copy;
        uint8_t submode_copy;
        uint8_t coding_info_copy;
    } subheader;
    uint8_t data[2328];
    */

    uint8_t data[2328 + 12 + 4 + 8];
};

// expected 2352
// 2328 + 12 + 4 + 8
// 2352-2304, so + 48

static const uint8_t m_CDXA_STEREO = 3;

struct PsxVideoFrameHeader
{
    unsigned short int mNumMdecCodes;
    unsigned short int m3800Magic;
    unsigned short int mQuantizationLevel;
    unsigned short int mVersion;
};

struct MasherVideoHeaderWrapper
{
    unsigned int mSectorType; // AKIK
    unsigned int mSectorNumber;

    // The 4 "unknown" / 0x80010160 in psx data is replaced by "AKIK" in PC data
    unsigned int mAkikMagic;

    unsigned short int mSectorNumberInFrame;
    unsigned short int mNumSectorsInFrame;
    unsigned int mFrameNum;
    unsigned int mFrameDataLen;
    unsigned short int mWidth;
    unsigned short int mHeight;

    PsxVideoFrameHeader mVideoFrameHeader;
    unsigned int mNulls;

    unsigned char frame[2016 + 240 + 4 + 4 + 4 + 2 + 2 + 4 + 4 + 2 + 2 + 2 + 2 + 2 + 2 + 4];

    // PsxVideoFrameHeader mVideoFrameHeader2;

    /*
    0000  char   {4}     "AKIK"

    // This is standard STR format data here

    0004  uint16 {2}     Sector number within frame (zero-based)
    0006  uint16 {2}     Number of sectors in frame
    0008  uint32 {4}     Frame number within file (one-based)
    000C  uint32 {4}     Frame data length
    0010  uint16 {2}     Video Width
    0012  uint16 {2}     Video Height

    0014  uint16 {2}     Number of MDEC codes divided by two, and rounded up to a multiple of 32
    0016  uint16 {2}     Always 0x3800
    0018  uint16 {2}     Quantization level of the video frame
    001A  uint16 {2}     Version of the video frame (always 2)
    001C  uint32 {4}     Always 0x00000000
    */

    //demultiplexing is joining all of the frame data into one buffer without the headers

};

std::vector<Uint32> pixels;

#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))

std::vector<unsigned char> ReadFrame(FILE* fp, bool& end, PSXMDECDecoder& mdec, PSXADPCMDecoder& adpcm, bool firstFrame, int& frameW, int& frameH)
{
    std::vector<unsigned char> r(32768);
    std::vector<unsigned char> outPtr(32678);

    unsigned int numSectorsToRead = 0;
    unsigned int sectorNumber = 0;
    const int kDataSize = 2016;
;

    for (;;)
    {
        MasherVideoHeaderWrapper w;

        if (fread(&w, 1, sizeof(w), fp) != sizeof(w))
        {
            end = true;
            return r;
        }

        if (w.mSectorType != 0x52494f4d)
        {
            // There is probably no way this is correct
            CDXASector* xa = (CDXASector*)&w;

            /*
            std::cout <<
                (CHECK_BIT(xa->subheader.coding_info, 0) ? "Mono " : "Stereo ") <<
                (CHECK_BIT(xa->subheader.coding_info, 2) ? "37800Hz " : "18900Hz ") <<
                (CHECK_BIT(xa->subheader.coding_info, 4) ? "4bit " : "8bit ")
                */

//                << std::endl;
           // if (xa->subheader.coding_info & 0xA)
            {

                auto numBytes = adpcm.DecodeFrameToPCM((int8_t *)outPtr.data(), &xa->data[0], true);
                //if (CHECK_BIT(xa->subheader.coding_info, 2) && (CHECK_BIT(xa->subheader.coding_info, 0)))
                {
                    AudioBuffer::mPlayedSamples = 0;
                    AudioBuffer::SendSamples((char*)outPtr.data(), numBytes);

                    // 8064
                    while (AudioBuffer::mPlayedSamples < numBytes/4)
                    {

                    }

                }
                //else
                {
               //     std::vector<unsigned char> silence;
                //    silence.resize(numBytes);
                //    AudioBuffer::SendSamples((char*)silence.data(), numBytes);
                }
            }

            // Must be VALE
            continue;
        }
        else
        {
            frameW = w.mWidth;
            frameH = w.mHeight;

            //std::cout << "sector: " << w.mSectorNumber << std::endl;
            //std::cout << "data len: " << w.mFrameDataLen << std::endl;
            //std::cout << "frame number: " << w.mFrameNum << std::endl;
            //std::cout << "num sectors in frame: " << w.mNumSectorsInFrame << std::endl;
            //std::cout << "frame sector number: " << w.mSectorNumberInFrame << std::endl;
            // SetSurfaceSize(w.mWidth, w.mHeight);

            uint32_t bytes_to_copy = w.mFrameDataLen - w.mSectorNumberInFrame *kDataSize;

            if (bytes_to_copy > 0)
            {
                if (bytes_to_copy > kDataSize)
                {
                    bytes_to_copy = kDataSize;
                }

                memcpy(r.data() + w.mSectorNumberInFrame * kDataSize, w.frame, bytes_to_copy);
            }

            if (w.mSectorNumberInFrame == w.mNumSectorsInFrame - 1)
            {
                break;
            }
        }
    }

    if (pixels.empty())
    {
        pixels.resize(frameW * frameH);

    }

    mdec.DecodeFrameToABGR32((uint16_t*)pixels.data(), (uint16_t*)r.data(), frameW, frameH, false);

    return r;
}

void Fmv::RenderVideoUi()
{

    if (!video && !mFp)
    {
        if (mFmvUis.empty())
        {
            auto fmvs = mGameData.Fmvs();
            for (auto fmvSet : fmvs)
            {
                mFmvUis.emplace_back(std::make_unique<FmvUi>());
            }
        }

        if (!mFmvUis.empty())
        {
            int i = 0;
            auto fmvs = mGameData.Fmvs();
            for (auto fmvSet : fmvs)
            {
                mFmvUis[i]->DrawVideoSelectionUi(video, mFp, videoFrame, fmvSet.first, fmvSet.second);
                i++;
            }
        }

    }
    else
    {
        if (mFp)
        {
            bool firstFrame = true;
            bool end = false;
            std::vector<unsigned char> frameData = ReadFrame(mFp, end, mMdec, mAdpcm, firstFrame, frameW, frameH);
            firstFrame = false;
            if (end)
            {
                fclose(mFp);
                mFp = nullptr;
            }
        }
        else if (video)
        {
            std::vector<Uint16> decodedFrame(video->SingleAudioFrameSizeBytes() * 2); // *2 if stereo

            if (!video->Update((Uint32*)videoFrame->pixels, (Uint8*)decodedFrame.data()))
            {
                SDL_ShowCursor(1);
                video = nullptr;
                if (videoFrame)
                {
                    SDL_FreeSurface(videoFrame);
                    videoFrame = nullptr;
                }
                //targetFps = 60;
            }
            else
            {
                AudioBuffer::SendSamples((char*)decodedFrame.data(), decodedFrame.size() * 2);
                while (AudioBuffer::mPlayedSamples < video->FrameNumber() * video->SingleAudioFrameSizeBytes())
                {

                }

            }
        }
    }
}

Fmv::Fmv(GameData& gameData)
    : mGameData(gameData)
{

}

Fmv::~Fmv()
{

}

void Fmv::Play()
{

}

void Fmv::Stop()
{
    SDL_ShowCursor(1);
    video = nullptr;
    if (videoFrame)
    {
        SDL_FreeSurface(videoFrame);
        videoFrame = nullptr;
    }
    if (mFp)
    {
        fclose(mFp);
        mFp = nullptr;
    }
}

void Fmv::Update()
{

}

void Fmv::Render()
{
    glEnable(GL_TEXTURE_2D);

    RenderVideoUi();

    if (videoFrame || mFp)
    {
        // TODO: Optimize - should use VBO's & update 1 texture rather than creating per frame
        GLuint TextureID = 0;

        glGenTextures(1, &TextureID);
        glBindTexture(GL_TEXTURE_2D, TextureID);

        int Mode = GL_RGB;
        /*
        if (videoFrame->format->BytesPerPixel == 4)
        {
            Mode = GL_RGBA;
        }
        */

        if (videoFrame)
        {
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, videoFrame->w, videoFrame->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, videoFrame->pixels);
        }
        else if (mFp)
        {
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, frameW, frameH, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
        }

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        // For Ortho mode, of course
        int X = -1;
        int Y = -1;
        int Width = 2;
        int Height = 2;

        glBegin(GL_QUADS);
        glTexCoord2f(0, 0); glVertex3f(X, Y, 0);
        glTexCoord2f(1, 0); glVertex3f(X + Width, Y, 0);
        glTexCoord2f(1, -1); glVertex3f(X + Width, Y + Height, 0);
        glTexCoord2f(0, -1); glVertex3f(X, Y + Height, 0);
        glEnd();

        glDeleteTextures(1, &TextureID);
    }

}
<commit_msg>fix crash on fmv size change<commit_after>#include "fmv.hpp"
#include "imgui/imgui.h"
#include "core/audiobuffer.hpp"
#include "gamedata.hpp"

#ifdef _WIN32
#include <windows.h>
#endif
#ifdef __APPLE__
#  include <OpenGL/gl.h>
#else
#  include <GL/gl.h>
#endif/*__APPLE__*/

std::vector<Uint32> pixels;

class FmvUi
{
private:
    char buf[4096];
    ImGuiTextFilter mFilter;
    int listbox_item_current = 1;
    std::vector<const char*> listbox_items;
public:
    FmvUi()
    {
#ifdef _WIN32
        strcpy(buf, "C:\\Program Files (x86)\\Steam\\SteamApps\\common\\Oddworld Abes Oddysee\\");
#else
        strcpy(buf, "/media/paul/FF7DISC3/Program Files (x86)/Steam/SteamApps/common/Oddworld Abes Oddysee/");
#endif
    }

    void DrawVideoSelectionUi(std::unique_ptr<Oddlib::Masher>& video, FILE*& fp, SDL_Surface*& videoFrame, const std::string& setName, const std::vector<std::string>& allFmvs)
    {
        std::string name = "Video player (" + setName + ")";
        ImGui::Begin(name.c_str(), nullptr, ImVec2(550, 580), 1.0f, ImGuiWindowFlags_NoCollapse);

        ImGui::InputText("Video path", buf, sizeof(buf));

        mFilter.Draw();

        listbox_items.resize(allFmvs.size());

        int matchingFilter = 0;
        for (size_t i = 0; i < allFmvs.size(); i++)
        {
            if (mFilter.PassFilter(allFmvs[i].c_str()))
            {
                listbox_items[matchingFilter] = allFmvs[i].c_str();
                matchingFilter++;
            }
        }
        ImGui::PushItemWidth(-1);
        ImGui::ListBox("##", &listbox_item_current, listbox_items.data(), matchingFilter, 27);

        if (ImGui::Button("Play", ImVec2(ImGui::GetWindowWidth(), 20)))
        {
            pixels.clear(); // In case next FMV has a diff resolution
            std::string fullPath = std::string(buf) + listbox_items[listbox_item_current];
            std::cout << "Play " << listbox_items[listbox_item_current] << std::endl;
            try
            {
                video = std::make_unique<Oddlib::Masher>(fullPath);
                if (videoFrame)
                {
                    SDL_FreeSurface(videoFrame);
                    videoFrame = nullptr;
                }

                if (video->HasAudio())
                {
                    AudioBuffer::ChangeAudioSpec(video->SingleAudioFrameSizeBytes(), video->AudioSampleRate());
                }

                if (video->HasVideo())
                {
                    videoFrame = SDL_CreateRGBSurface(0, video->Width(), video->Height(), 32, 0, 0, 0, 0);
                    //                    targetFps = video->FrameRate() * 2;
                }

                SDL_ShowCursor(0);
            }
            catch (const Oddlib::Exception& ex)
            {
                // ImGui::Text(ex.what());

                fp = fopen(fullPath.c_str(), "rb");
                AudioBuffer::ChangeAudioSpec(8064/4, 37800);

            }
        }

        ImGui::End();
    }
};

struct CDXASector
{
    /*
    uint8_t sync[12];
    uint8_t header[4];

    struct CDXASubHeader
    {
        uint8_t file_number;
        uint8_t channel;
        uint8_t submode;
        uint8_t coding_info;
        uint8_t file_number_copy;
        uint8_t channel_number_copy;
        uint8_t submode_copy;
        uint8_t coding_info_copy;
    } subheader;
    uint8_t data[2328];
    */

    uint8_t data[2328 + 12 + 4 + 8];
};

// expected 2352
// 2328 + 12 + 4 + 8
// 2352-2304, so + 48

static const uint8_t m_CDXA_STEREO = 3;

struct PsxVideoFrameHeader
{
    unsigned short int mNumMdecCodes;
    unsigned short int m3800Magic;
    unsigned short int mQuantizationLevel;
    unsigned short int mVersion;
};

struct MasherVideoHeaderWrapper
{
    unsigned int mSectorType; // AKIK
    unsigned int mSectorNumber;

    // The 4 "unknown" / 0x80010160 in psx data is replaced by "AKIK" in PC data
    unsigned int mAkikMagic;

    unsigned short int mSectorNumberInFrame;
    unsigned short int mNumSectorsInFrame;
    unsigned int mFrameNum;
    unsigned int mFrameDataLen;
    unsigned short int mWidth;
    unsigned short int mHeight;

    PsxVideoFrameHeader mVideoFrameHeader;
    unsigned int mNulls;

    unsigned char frame[2016 + 240 + 4 + 4 + 4 + 2 + 2 + 4 + 4 + 2 + 2 + 2 + 2 + 2 + 2 + 4];

    // PsxVideoFrameHeader mVideoFrameHeader2;

    /*
    0000  char   {4}     "AKIK"

    // This is standard STR format data here

    0004  uint16 {2}     Sector number within frame (zero-based)
    0006  uint16 {2}     Number of sectors in frame
    0008  uint32 {4}     Frame number within file (one-based)
    000C  uint32 {4}     Frame data length
    0010  uint16 {2}     Video Width
    0012  uint16 {2}     Video Height

    0014  uint16 {2}     Number of MDEC codes divided by two, and rounded up to a multiple of 32
    0016  uint16 {2}     Always 0x3800
    0018  uint16 {2}     Quantization level of the video frame
    001A  uint16 {2}     Version of the video frame (always 2)
    001C  uint32 {4}     Always 0x00000000
    */

    //demultiplexing is joining all of the frame data into one buffer without the headers

};

#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))

std::vector<unsigned char> ReadFrame(FILE* fp, bool& end, PSXMDECDecoder& mdec, PSXADPCMDecoder& adpcm, bool firstFrame, int& frameW, int& frameH)
{
    std::vector<unsigned char> r(32768);
    std::vector<unsigned char> outPtr(32678);

    unsigned int numSectorsToRead = 0;
    unsigned int sectorNumber = 0;
    const int kDataSize = 2016;
;

    for (;;)
    {
        MasherVideoHeaderWrapper w;

        if (fread(&w, 1, sizeof(w), fp) != sizeof(w))
        {
            end = true;
            return r;
        }

        if (w.mSectorType != 0x52494f4d)
        {
            // There is probably no way this is correct
            CDXASector* xa = (CDXASector*)&w;

            /*
            std::cout <<
                (CHECK_BIT(xa->subheader.coding_info, 0) ? "Mono " : "Stereo ") <<
                (CHECK_BIT(xa->subheader.coding_info, 2) ? "37800Hz " : "18900Hz ") <<
                (CHECK_BIT(xa->subheader.coding_info, 4) ? "4bit " : "8bit ")
                */

//                << std::endl;
           // if (xa->subheader.coding_info & 0xA)
            {

                auto numBytes = adpcm.DecodeFrameToPCM((int8_t *)outPtr.data(), &xa->data[0], true);
                //if (CHECK_BIT(xa->subheader.coding_info, 2) && (CHECK_BIT(xa->subheader.coding_info, 0)))
                {
                    AudioBuffer::mPlayedSamples = 0;
                    AudioBuffer::SendSamples((char*)outPtr.data(), numBytes);

                    // 8064
                    while (AudioBuffer::mPlayedSamples < numBytes/4)
                    {

                    }

                }
                //else
                {
               //     std::vector<unsigned char> silence;
                //    silence.resize(numBytes);
                //    AudioBuffer::SendSamples((char*)silence.data(), numBytes);
                }
            }

            // Must be VALE
            continue;
        }
        else
        {
            frameW = w.mWidth;
            frameH = w.mHeight;

            //std::cout << "sector: " << w.mSectorNumber << std::endl;
            //std::cout << "data len: " << w.mFrameDataLen << std::endl;
            //std::cout << "frame number: " << w.mFrameNum << std::endl;
            //std::cout << "num sectors in frame: " << w.mNumSectorsInFrame << std::endl;
            //std::cout << "frame sector number: " << w.mSectorNumberInFrame << std::endl;
            // SetSurfaceSize(w.mWidth, w.mHeight);

            uint32_t bytes_to_copy = w.mFrameDataLen - w.mSectorNumberInFrame *kDataSize;

            if (bytes_to_copy > 0)
            {
                if (bytes_to_copy > kDataSize)
                {
                    bytes_to_copy = kDataSize;
                }

                memcpy(r.data() + w.mSectorNumberInFrame * kDataSize, w.frame, bytes_to_copy);
            }

            if (w.mSectorNumberInFrame == w.mNumSectorsInFrame - 1)
            {
                break;
            }
        }
    }

    if (pixels.empty())
    {
        pixels.resize(frameW * frameH);

    }

    mdec.DecodeFrameToABGR32((uint16_t*)pixels.data(), (uint16_t*)r.data(), frameW, frameH, false);

    return r;
}

void Fmv::RenderVideoUi()
{

    if (!video && !mFp)
    {
        if (mFmvUis.empty())
        {
            auto fmvs = mGameData.Fmvs();
            for (auto fmvSet : fmvs)
            {
                mFmvUis.emplace_back(std::make_unique<FmvUi>());
            }
        }

        if (!mFmvUis.empty())
        {
            int i = 0;
            auto fmvs = mGameData.Fmvs();
            for (auto fmvSet : fmvs)
            {
                mFmvUis[i]->DrawVideoSelectionUi(video, mFp, videoFrame, fmvSet.first, fmvSet.second);
                i++;
            }
        }

    }
    else
    {
        if (mFp)
        {
            bool firstFrame = true;
            bool end = false;
            std::vector<unsigned char> frameData = ReadFrame(mFp, end, mMdec, mAdpcm, firstFrame, frameW, frameH);
            firstFrame = false;
            if (end)
            {
                fclose(mFp);
                mFp = nullptr;
            }
        }
        else if (video)
        {
            std::vector<Uint16> decodedFrame(video->SingleAudioFrameSizeBytes() * 2); // *2 if stereo

            if (!video->Update((Uint32*)videoFrame->pixels, (Uint8*)decodedFrame.data()))
            {
                SDL_ShowCursor(1);
                video = nullptr;
                if (videoFrame)
                {
                    SDL_FreeSurface(videoFrame);
                    videoFrame = nullptr;
                }
                //targetFps = 60;
            }
            else
            {
                AudioBuffer::SendSamples((char*)decodedFrame.data(), decodedFrame.size() * 2);
                while (AudioBuffer::mPlayedSamples < video->FrameNumber() * video->SingleAudioFrameSizeBytes())
                {

                }

            }
        }
    }
}

Fmv::Fmv(GameData& gameData)
    : mGameData(gameData)
{

}

Fmv::~Fmv()
{

}

void Fmv::Play()
{

}

void Fmv::Stop()
{
    SDL_ShowCursor(1);
    video = nullptr;
    if (videoFrame)
    {
        SDL_FreeSurface(videoFrame);
        videoFrame = nullptr;
    }
    if (mFp)
    {
        fclose(mFp);
        mFp = nullptr;
    }
}

void Fmv::Update()
{

}

void Fmv::Render()
{
    glEnable(GL_TEXTURE_2D);

    RenderVideoUi();

    if (videoFrame || mFp)
    {
        // TODO: Optimize - should use VBO's & update 1 texture rather than creating per frame
        GLuint TextureID = 0;

        glGenTextures(1, &TextureID);
        glBindTexture(GL_TEXTURE_2D, TextureID);

        int Mode = GL_RGB;
        /*
        if (videoFrame->format->BytesPerPixel == 4)
        {
            Mode = GL_RGBA;
        }
        */

        if (videoFrame)
        {
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, videoFrame->w, videoFrame->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, videoFrame->pixels);
        }
        else if (mFp)
        {
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, frameW, frameH, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
        }

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        // For Ortho mode, of course
        int X = -1;
        int Y = -1;
        int Width = 2;
        int Height = 2;

        glBegin(GL_QUADS);
        glTexCoord2f(0, 0); glVertex3f(X, Y, 0);
        glTexCoord2f(1, 0); glVertex3f(X + Width, Y, 0);
        glTexCoord2f(1, -1); glVertex3f(X + Width, Y + Height, 0);
        glTexCoord2f(0, -1); glVertex3f(X, Y + Height, 0);
        glEnd();

        glDeleteTextures(1, &TextureID);
    }

}
<|endoftext|>


<commit_before>//
// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

#include "AnalyzeCallDepth.h"

AnalyzeCallDepth::FunctionNode::FunctionNode(TIntermAggregate *node) : node(node)
{
	visit = PreVisit;
	callDepth = 0;
}

const TString &AnalyzeCallDepth::FunctionNode::getName() const
{
	return node->getName();
}

void AnalyzeCallDepth::FunctionNode::addCallee(AnalyzeCallDepth::FunctionNode *callee)
{
    for(size_t i = 0; i < callees.size(); i++)
	{
        if(callees[i] == callee)
		{
            return;
		}
    }

    callees.push_back(callee);
}

unsigned int AnalyzeCallDepth::FunctionNode::analyzeCallDepth(AnalyzeCallDepth *analyzeCallDepth)
{
    ASSERT(visit == PreVisit);
    ASSERT(analyzeCallDepth);

    callDepth = 0;
    visit = InVisit;

    for(size_t i = 0; i < callees.size(); i++)
	{
        switch(callees[i]->visit)
		{
        case InVisit:
            // Cycle detected (recursion)
            return UINT_MAX;
        case PostVisit:
			callDepth = std::max(callDepth, 1 + callees[i]->getLastDepth());
            break;
        case PreVisit:
			callDepth = std::max(callDepth, 1 + callees[i]->analyzeCallDepth(analyzeCallDepth));
			break;
        default:
            UNREACHABLE(callees[i]->visit);
            break;
        }
    }

    visit = PostVisit;
    return callDepth;
}

unsigned int AnalyzeCallDepth::FunctionNode::getLastDepth() const
{
	return callDepth;
}

void AnalyzeCallDepth::FunctionNode::removeIfUnreachable()
{
	if(visit == PreVisit)
	{
		node->setOp(EOpPrototype);
		node->getSequence().resize(1);   // Remove function body
	}
}

AnalyzeCallDepth::AnalyzeCallDepth(TIntermNode *root)
    : TIntermTraverser(true, false, true, false),
      currentFunction(0)
{
	root->traverse(this);
}

AnalyzeCallDepth::~AnalyzeCallDepth()
{
    for(size_t i = 0; i < functions.size(); i++)
	{
        delete functions[i];
	}
}

bool AnalyzeCallDepth::visitAggregate(Visit visit, TIntermAggregate *node)
{
    switch(node->getOp())
    {
    case EOpFunction:   // Function definition
		{
			if(visit == PreVisit)
			{
				currentFunction = findFunctionByName(node->getName());

				if(!currentFunction)
				{
					currentFunction = new FunctionNode(node);
					functions.push_back(currentFunction);
				}
			}
			else if(visit == PostVisit)
			{
				currentFunction = 0;
			}
		}
        break;
    case EOpFunctionCall:
		{
			if(!node->isUserDefined())
			{
				return true;   // Check the arguments for function calls
			}

			if(visit == PreVisit)
			{
				FunctionNode *function = findFunctionByName(node->getName());

				if(!function)
				{
					function = new FunctionNode(node);
					functions.push_back(function);
				}

				if(currentFunction)
				{
					currentFunction->addCallee(function);
				}
				else
				{
					globalFunctionCalls.insert(function);
				}
			}
		}
        break;
    default:
        break;
    }

    return true;
}

unsigned int AnalyzeCallDepth::analyzeCallDepth()
{
    FunctionNode *main = findFunctionByName("main(");

	if(!main)
	{
		return 0;
	}

    unsigned int depth = 1 + main->analyzeCallDepth(this);

	for(FunctionSet::iterator globalCall = globalFunctionCalls.begin(); globalCall != globalFunctionCalls.end(); globalCall++)
	{
		unsigned int globalDepth = 1 + (*globalCall)->analyzeCallDepth(this);

		if(globalDepth > depth)
		{
			depth = globalDepth;
		}
	}

	for(size_t i = 0; i < functions.size(); i++)
	{
		functions[i]->removeIfUnreachable();
    }

    return depth;
}

AnalyzeCallDepth::FunctionNode *AnalyzeCallDepth::findFunctionByName(const TString &name)
{
    for(size_t i = 0; i < functions.size(); i++)
	{
        if(functions[i]->getName() == name)
		{
            return functions[i];
		}
    }

    return 0;
}

<commit_msg>Fixed recursion analysis<commit_after>//
// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

#include "AnalyzeCallDepth.h"

AnalyzeCallDepth::FunctionNode::FunctionNode(TIntermAggregate *node) : node(node)
{
	visit = PreVisit;
	callDepth = 0;
}

const TString &AnalyzeCallDepth::FunctionNode::getName() const
{
	return node->getName();
}

void AnalyzeCallDepth::FunctionNode::addCallee(AnalyzeCallDepth::FunctionNode *callee)
{
    for(size_t i = 0; i < callees.size(); i++)
	{
        if(callees[i] == callee)
		{
            return;
		}
    }

    callees.push_back(callee);
}

unsigned int AnalyzeCallDepth::FunctionNode::analyzeCallDepth(AnalyzeCallDepth *analyzeCallDepth)
{
    ASSERT(visit == PreVisit);
    ASSERT(analyzeCallDepth);

    callDepth = 0;
    visit = InVisit;

    for(size_t i = 0; i < callees.size(); i++)
	{
		unsigned int calleeDepth = 0;
        switch(callees[i]->visit)
		{
        case InVisit:
            // Cycle detected (recursion)
            return UINT_MAX;
        case PostVisit:
			calleeDepth = callees[i]->getLastDepth();
            break;
        case PreVisit:
			calleeDepth = callees[i]->analyzeCallDepth(analyzeCallDepth);
			break;
        default:
            UNREACHABLE(callees[i]->visit);
            break;
        }
		if(calleeDepth != UINT_MAX) ++calleeDepth;
		callDepth = std::max(callDepth, calleeDepth);
    }

    visit = PostVisit;
    return callDepth;
}

unsigned int AnalyzeCallDepth::FunctionNode::getLastDepth() const
{
	return callDepth;
}

void AnalyzeCallDepth::FunctionNode::removeIfUnreachable()
{
	if(visit == PreVisit)
	{
		node->setOp(EOpPrototype);
		node->getSequence().resize(1);   // Remove function body
	}
}

AnalyzeCallDepth::AnalyzeCallDepth(TIntermNode *root)
    : TIntermTraverser(true, false, true, false),
      currentFunction(0)
{
	root->traverse(this);
}

AnalyzeCallDepth::~AnalyzeCallDepth()
{
    for(size_t i = 0; i < functions.size(); i++)
	{
        delete functions[i];
	}
}

bool AnalyzeCallDepth::visitAggregate(Visit visit, TIntermAggregate *node)
{
    switch(node->getOp())
    {
    case EOpFunction:   // Function definition
		{
			if(visit == PreVisit)
			{
				currentFunction = findFunctionByName(node->getName());

				if(!currentFunction)
				{
					currentFunction = new FunctionNode(node);
					functions.push_back(currentFunction);
				}
			}
			else if(visit == PostVisit)
			{
				currentFunction = 0;
			}
		}
        break;
    case EOpFunctionCall:
		{
			if(!node->isUserDefined())
			{
				return true;   // Check the arguments for function calls
			}

			if(visit == PreVisit)
			{
				FunctionNode *function = findFunctionByName(node->getName());

				if(!function)
				{
					function = new FunctionNode(node);
					functions.push_back(function);
				}

				if(currentFunction)
				{
					currentFunction->addCallee(function);
				}
				else
				{
					globalFunctionCalls.insert(function);
				}
			}
		}
        break;
    default:
        break;
    }

    return true;
}

unsigned int AnalyzeCallDepth::analyzeCallDepth()
{
    FunctionNode *main = findFunctionByName("main(");

	if(!main)
	{
		return 0;
	}

    unsigned int depth = main->analyzeCallDepth(this);
	if(depth != UINT_MAX) ++depth;

	for(FunctionSet::iterator globalCall = globalFunctionCalls.begin(); globalCall != globalFunctionCalls.end(); globalCall++)
	{
		unsigned int globalDepth = (*globalCall)->analyzeCallDepth(this);
		if(globalDepth != UINT_MAX) ++globalDepth;

		if(globalDepth > depth)
		{
			depth = globalDepth;
		}
	}

	for(size_t i = 0; i < functions.size(); i++)
	{
		functions[i]->removeIfUnreachable();
    }

    return depth;
}

AnalyzeCallDepth::FunctionNode *AnalyzeCallDepth::findFunctionByName(const TString &name)
{
    for(size_t i = 0; i < functions.size(); i++)
	{
        if(functions[i]->getName() == name)
		{
            return functions[i];
		}
    }

    return 0;
}

<|endoftext|>


<commit_before>/*
 *Copyright (c) 2013-2013, yinqiwen <yinqiwen@gmail.com>
 *All rights reserved.
 *
 *Redistribution and use in source and binary forms, with or without
 *modification, are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *  * Neither the name of Redis nor the names of its contributors may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 *THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "db.hpp"
#include "ardb_server.hpp"
#include "geo/geohash_helper.hpp"
#include <algorithm>

namespace ardb
{
    /*
     *  GEOADD key MERCATOR|WGS84 x y value  [attr_name attr_value ...]
     */
    int ArdbServer::GeoAdd(ArdbConnContext& ctx, RedisCommandFrame& cmd)
    {
        GeoAddOptions options;
        std::string err;
        if (0 != options.Parse(cmd.GetArguments(), err, 1))
        {
            fill_error_reply(ctx.reply, "%s", err.c_str());
            return 0;
        }
        int ret = m_db->GeoAdd(ctx.currentDB, cmd.GetArguments()[0], options);
        if (ret >= 0)
        {
            fill_status_reply(ctx.reply, "OK");
        }
        else
        {
            fill_error_reply(ctx.reply, "Failed to %s", cmd.ToString().c_str());
        }
        return 0;
    }

    /*
     *  GEOSEARCH key MERCATOR|WGS84 x y  <GeoOptions>
     *  GEOSEARCH key MEMBER m
     *
     *  <GeoOptions> = IN N m0 m1 m2 RADIUS r
     *                 [ASC|DESC] [WITHCOORDINATES] [WITHDISTANCES]
     *                 [GET pattern [GET pattern ...]]
     *                 [INCLUDE key_pattern value_pattern [INCLUDE key_pattern value_pattern ...]]
     *                 [EXCLUDE key_pattern value_pattern [EXCLUDE key_pattern value_pattern ...]]
     *                 [LIMIT offset count]
     *
     *  For 'GET pattern' in GEOSEARCH:
     *  If 'pattern' is '#.<attr>',  return actual point's attribute stored by 'GeoAdd'
     *  Other pattern would processed the same as 'sort' command (Use same C++ function),
     *  The patterns like '#', "*->field" are valid.
     */

    int ArdbServer::GeoSearch(ArdbConnContext& ctx, RedisCommandFrame& cmd)
    {
        GeoSearchOptions options;
        std::string err;
        if (0 != options.Parse(cmd.GetArguments(), err, 1))
        {
            fill_error_reply(ctx.reply, "%s", err.c_str());
            return 0;
        }
        ValueDataDeque res;
        m_db->GeoSearch(ctx.currentDB, cmd.GetArguments()[0], options, res);
        fill_array_reply(ctx.reply, res);
        return 0;
    }

    int Ardb::GeoAdd(const DBID& db, const Slice& key, const GeoAddOptions& options)
    {
        GeoHashRange lat_range, lon_range;
        GeoHashHelper::GetCoordRange(options.coord_type, lat_range, lon_range);
        if (options.x < lon_range.min || options.x > lon_range.max || options.y < lat_range.min
                || options.y > lat_range.max)
        {
            return ERR_INVALID_ARGS;
        }
        GeoPoint point;
        point.x = options.x;
        point.y = options.y;

        if (options.coord_type == GEO_WGS84_TYPE)
        {
            point.x = GeoHashHelper::GetMercatorX(options.x);
            point.y = GeoHashHelper::GetMercatorY(options.y);
            GeoHashHelper::GetCoordRange(GEO_MERCATOR_TYPE, lat_range, lon_range);
        }
        point.attrs = options.attrs;

        GeoHashBits hash;
        geohash_encode(&lat_range, &lon_range, point.y, point.x, 26, &hash);
        GeoHashFix52Bits score = hash.bits;
        ValueData score_value;
        score_value.SetIntValue((int64) score);

        Buffer content;
        point.Encode(content);
        Slice content_value(content.GetRawReadBuffer(), content.ReadableBytes());
        return ZAdd(db, key, score_value, options.value, content_value);
    }

    static bool less_by_distance(const GeoPoint& v1, const GeoPoint& v2)
    {
        return v1.distance < v2.distance;
    }

    static bool great_by_distance(const GeoPoint& v1, const GeoPoint& v2)
    {
        return v1.distance > v2.distance;
    }

    static int ZSetValueStoreCallback(const ValueData& value, int cursor, void* cb)
    {
        ValueDataArray* s = (ValueDataArray*) cb;
        s->push_back(value);
        return 0;
    }

    int Ardb::GeoSearch(const DBID& db, const Slice& key, const GeoSearchOptions& options, ValueDataDeque& results)
    {
        uint64 start_time = get_current_epoch_micros();
        GeoHashBitsSet ress;
        double x = options.x, y = options.y;
        if (options.coord_type == GEO_WGS84_TYPE)
        {
            x = GeoHashHelper::GetMercatorX(options.x);
            y = GeoHashHelper::GetMercatorY(options.y);
        }
        if (options.by_member)
        {
            ValueData score, attr;
            int err = ZGetNodeValue(db, key, options.member, score, attr);
            if (0 != err)
            {
                return err;
            }
            Buffer attr_content(const_cast<char*>(attr.bytes_value.data()), 0, attr.bytes_value.size());
            GeoPoint point;
            point.Decode(attr_content);
            x = point.x;
            y = point.y;
        }
        ZSetCacheElementSet subset;
        if (options.in_members)
        {
            StringSet::const_iterator sit = options.submembers.begin();
            while (sit != options.submembers.end())
            {
                ZSetCaheElement ele;
                ele.value = *sit;
                ValueData score, attr;
                if (0 == ZGetNodeValue(db, key, ele.value, score, attr))
                {
                    ele.score = score.NumberValue();
                    Buffer buf2;
                    attr.Encode(buf2);
                    ele.attr.assign(buf2.GetRawReadBuffer(), buf2.ReadableBytes());
                    subset.insert(ele);
                }
                sit++;
            }
        }
        GeoHashHelper::GetAreasByRadius(GEO_MERCATOR_TYPE, y, x, options.radius, ress);

        /*
         * Merge areas if possible to avoid disk search
         */
        std::vector<ZRangeSpec> range_array;
        GeoHashBitsSet::iterator rit = ress.begin();
        GeoHashBitsSet::iterator next_it = ress.begin();
        next_it++;
        while (rit != ress.end())
        {
            GeoHashBits& hash = *rit;
            GeoHashBits next = hash;
            next.bits++;
            while (next_it != ress.end() && next.bits == next_it->bits)
            {
                next.bits++;
                next_it++;
                rit++;
            }
            ZRangeSpec range;
            range.contain_min = true;
            range.contain_max = false;
            range.min.SetIntValue(GeoHashHelper::Allign52Bits(hash));
            range.max.SetIntValue(GeoHashHelper::Allign52Bits(next));
            range_array.push_back(range);
            rit++;
            next_it++;
        }
        DEBUG_LOG("After areas merging, reduce searching area size from %u to %u", ress.size(), range_array.size());

        GeoPointArray points;
        std::vector<ZRangeSpec>::iterator hit = range_array.begin();
        Iterator* iter = NULL;
        while (hit != range_array.end())
        {
            ZSetQueryOptions z_options;
            z_options.withscores = false;
            z_options.withattr = true;
            ValueDataArray values;
            if (options.in_members)
            {
                ZSetCache::GetRangeInZSetCache(subset, *hit, z_options.withscores, z_options.withattr,
                        ZSetValueStoreCallback, &values);
            }
            else
            {
                ZRangeByScoreRange(db, key, *hit, iter, z_options, true, ZSetValueStoreCallback, &values);
            }
            ValueDataArray::iterator vit = values.begin();
            while (vit != values.end())
            {
                GeoPoint point;
                vit->ToString(point.value);
                //attributes
                vit++;
                Buffer content(const_cast<char*>(vit->bytes_value.data()), 0, vit->bytes_value.size());
                if (point.Decode(content))
                {
                    if (GeoHashHelper::GetDistanceSquareIfInRadius(GEO_MERCATOR_TYPE, x, y, point.x, point.y,
                            options.radius, point.distance))
                    {
                        /*
                         * filter by exclude/include
                         */
                        if (!options.includes.empty() || !options.excludes.empty())
                        {
                            ValueData subst;
                            subst.SetValue(point.value, false);
                            bool matched = options.includes.empty() ? true : false;
                            if (!options.includes.empty())
                            {
                                StringStringMap::const_iterator sit = options.includes.begin();
                                while (sit != options.includes.end())
                                {
                                    ValueData mv;
                                    if (0 != MatchValueByPattern(db, sit->first, sit->second, subst, mv))
                                    {
                                        matched = false;
                                        break;
                                    }
                                    else
                                    {
                                        matched = true;
                                    }
                                    sit++;
                                }
                            }
                            if (matched && !options.excludes.empty())
                            {
                                StringStringMap::const_iterator sit = options.excludes.begin();
                                while (sit != options.excludes.end())
                                {
                                    ValueData mv;
                                    if (0 == MatchValueByPattern(db, sit->first, sit->second, subst, mv))
                                    {
                                        matched = false;
                                        break;
                                    }
                                    else
                                    {
                                        matched = true;
                                    }
                                    sit++;
                                }
                            }

                            if (matched)
                            {
                                points.push_back(point);
                            }
                        }
                        else
                        {
                            points.push_back(point);
                        }
                    }
                    else
                    {
                        //DEBUG_LOG("%s is not in radius:%.2fm", point.value.c_str(), options.radius);
                    }
                }
                else
                {
                    WARN_LOG("Failed to decode geo point.");
                }
                vit++;
            }
            hit++;
        }
        DELETE(iter);
        if (!options.nosort)
        {
            std::sort(points.begin(), points.end(), options.asc ? less_by_distance : great_by_distance);
        }

        if (options.offset > 0)
        {
            if ((uint32) options.offset > points.size())
            {
                points.clear();
            }
            else
            {
                GeoPointArray::iterator start = points.begin() + options.offset;
                points.erase(points.begin(), start);
            }
        }
        if (options.limit > 0)
        {
            if ((uint32) options.limit < points.size())
            {
                GeoPointArray::iterator end = points.begin() + options.limit;
                points.erase(end, points.end());
            }
        }
        GeoPointArray::iterator pit = points.begin();
        while (pit != points.end())
        {
            ValueData v;
            v.SetValue(pit->value, false);
            results.push_back(v);
            GeoGetOptionDeque::const_iterator ait = options.get_patterns.begin();
            while (ait != options.get_patterns.end())
            {
                ValueData attr;
                if (ait->get_distances)
                {
                    attr.SetDoubleValue(sqrt(pit->distance));
                    results.push_back(attr);
                }
                else if (ait->get_coodinates)
                {
                    if (options.coord_type == GEO_WGS84_TYPE)
                    {
                        pit->x = GeoHashHelper::GetWGS84X(pit->x);
                        pit->y = GeoHashHelper::GetWGS84Y(pit->y);
                    }
                    attr.SetDoubleValue(pit->x);
                    results.push_back(attr);
                    attr.SetDoubleValue(pit->y);
                    results.push_back(attr);
                }
                else if (ait->get_attr)
                {
                    StringStringMap::iterator found = pit->attrs.find(ait->get_pattern);
                    if (found != pit->attrs.end())
                    {
                        attr.SetValue(found->second, false);
                    }
                    results.push_back(attr);
                }
                else
                {
                    GetValueByPattern(db, ait->get_pattern, v, attr);
                    results.push_back(attr);
                }
                ait++;
            }
            pit++;
        }
        uint64 end_time = get_current_epoch_micros();
        DEBUG_LOG("Cost %llu microseconds to search.", end_time - start_time);
        return 0;
    }
}

<commit_msg>fix for geosearch<commit_after>/*
 *Copyright (c) 2013-2013, yinqiwen <yinqiwen@gmail.com>
 *All rights reserved.
 *
 *Redistribution and use in source and binary forms, with or without
 *modification, are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *  * Neither the name of Redis nor the names of its contributors may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 *BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 *THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "db.hpp"
#include "ardb_server.hpp"
#include "geo/geohash_helper.hpp"
#include <algorithm>

namespace ardb
{
    /*
     *  GEOADD key MERCATOR|WGS84 x y value  [attr_name attr_value ...]
     */
    int ArdbServer::GeoAdd(ArdbConnContext& ctx, RedisCommandFrame& cmd)
    {
        GeoAddOptions options;
        std::string err;
        if (0 != options.Parse(cmd.GetArguments(), err, 1))
        {
            fill_error_reply(ctx.reply, "%s", err.c_str());
            return 0;
        }
        int ret = m_db->GeoAdd(ctx.currentDB, cmd.GetArguments()[0], options);
        if (ret >= 0)
        {
            fill_status_reply(ctx.reply, "OK");
        }
        else
        {
            fill_error_reply(ctx.reply, "Failed to %s", cmd.ToString().c_str());
        }
        return 0;
    }

    /*
     *  GEOSEARCH key MERCATOR|WGS84 x y  <GeoOptions>
     *  GEOSEARCH key MEMBER m
     *
     *  <GeoOptions> = IN N m0 m1 m2 RADIUS r
     *                 [ASC|DESC] [WITHCOORDINATES] [WITHDISTANCES]
     *                 [GET pattern [GET pattern ...]]
     *                 [INCLUDE key_pattern value_pattern [INCLUDE key_pattern value_pattern ...]]
     *                 [EXCLUDE key_pattern value_pattern [EXCLUDE key_pattern value_pattern ...]]
     *                 [LIMIT offset count]
     *
     *  For 'GET pattern' in GEOSEARCH:
     *  If 'pattern' is '#.<attr>',  return actual point's attribute stored by 'GeoAdd'
     *  Other pattern would processed the same as 'sort' command (Use same C++ function),
     *  The patterns like '#', "*->field" are valid.
     */

    int ArdbServer::GeoSearch(ArdbConnContext& ctx, RedisCommandFrame& cmd)
    {
        GeoSearchOptions options;
        std::string err;
        if (0 != options.Parse(cmd.GetArguments(), err, 1))
        {
            fill_error_reply(ctx.reply, "%s", err.c_str());
            return 0;
        }
        ValueDataDeque res;
        m_db->GeoSearch(ctx.currentDB, cmd.GetArguments()[0], options, res);
        fill_array_reply(ctx.reply, res);
        return 0;
    }

    int Ardb::GeoAdd(const DBID& db, const Slice& key, const GeoAddOptions& options)
    {
        GeoHashRange lat_range, lon_range;
        GeoHashHelper::GetCoordRange(options.coord_type, lat_range, lon_range);
        if (options.x < lon_range.min || options.x > lon_range.max || options.y < lat_range.min
                || options.y > lat_range.max)
        {
            return ERR_INVALID_ARGS;
        }
        GeoPoint point;
        point.x = options.x;
        point.y = options.y;

        if (options.coord_type == GEO_WGS84_TYPE)
        {
            point.x = GeoHashHelper::GetMercatorX(options.x);
            point.y = GeoHashHelper::GetMercatorY(options.y);
            GeoHashHelper::GetCoordRange(GEO_MERCATOR_TYPE, lat_range, lon_range);
        }
        point.attrs = options.attrs;

        GeoHashBits hash;
        geohash_encode(&lat_range, &lon_range, point.y, point.x, 26, &hash);
        GeoHashFix52Bits score = hash.bits;
        ValueData score_value;
        score_value.SetIntValue((int64) score);

        Buffer content;
        point.Encode(content);
        Slice content_value(content.GetRawReadBuffer(), content.ReadableBytes());
        return ZAdd(db, key, score_value, options.value, content_value);
    }

    static bool less_by_distance(const GeoPoint& v1, const GeoPoint& v2)
    {
        return v1.distance < v2.distance;
    }

    static bool great_by_distance(const GeoPoint& v1, const GeoPoint& v2)
    {
        return v1.distance > v2.distance;
    }

    static int ZSetValueStoreCallback(const ValueData& value, int cursor, void* cb)
    {
        ValueDataArray* s = (ValueDataArray*) cb;
        s->push_back(value);
        return 0;
    }

    int Ardb::GeoSearch(const DBID& db, const Slice& key, const GeoSearchOptions& options, ValueDataDeque& results)
    {
        uint64 start_time = get_current_epoch_micros();
        GeoHashBitsSet ress;
        double x = options.x, y = options.y;
        if (options.coord_type == GEO_WGS84_TYPE)
        {
            x = GeoHashHelper::GetMercatorX(options.x);
            y = GeoHashHelper::GetMercatorY(options.y);
        }
        if (options.by_member)
        {
            ValueData score, attr;
            int err = ZGetNodeValue(db, key, options.member, score, attr);
            if (0 != err)
            {
                return err;
            }
            Buffer attr_content(const_cast<char*>(attr.bytes_value.data()), 0, attr.bytes_value.size());
            GeoPoint point;
            point.Decode(attr_content);
            x = point.x;
            y = point.y;
        }
        ZSetCacheElementSet subset;
        if (options.in_members)
        {
            StringSet::const_iterator sit = options.submembers.begin();
            while (sit != options.submembers.end())
            {
                ZSetCaheElement ele;

                ValueData score, attr;
                if (0 == ZGetNodeValue(db, key, *sit, score, attr))
                {
                    ele.score = score.NumberValue();
                    Buffer buf1, buf2;
                    ValueData vv;
                    vv.SetValue(*sit, true);
                    vv.Encode(buf1);
                    attr.Encode(buf2);
                    ele.value.assign(buf1.GetRawReadBuffer(), buf1.ReadableBytes());
                    ele.attr.assign(buf2.GetRawReadBuffer(), buf2.ReadableBytes());
                    subset.insert(ele);
                }
                sit++;
            }
        }
        GeoHashHelper::GetAreasByRadius(GEO_MERCATOR_TYPE, y, x, options.radius, ress);

        /*
         * Merge areas if possible to avoid disk search
         */
        std::vector<ZRangeSpec> range_array;
        GeoHashBitsSet::iterator rit = ress.begin();
        GeoHashBitsSet::iterator next_it = ress.begin();
        next_it++;
        while (rit != ress.end())
        {
            GeoHashBits& hash = *rit;
            GeoHashBits next = hash;
            next.bits++;
            while (next_it != ress.end() && next.bits == next_it->bits)
            {
                next.bits++;
                next_it++;
                rit++;
            }
            ZRangeSpec range;
            range.contain_min = true;
            range.contain_max = false;
            range.min.SetIntValue(GeoHashHelper::Allign52Bits(hash));
            range.max.SetIntValue(GeoHashHelper::Allign52Bits(next));
            range_array.push_back(range);
            rit++;
            next_it++;
        }
        DEBUG_LOG("After areas merging, reduce searching area size from %u to %u", ress.size(), range_array.size());

        GeoPointArray points;
        std::vector<ZRangeSpec>::iterator hit = range_array.begin();
        Iterator* iter = NULL;
        while (hit != range_array.end())
        {
            ZSetQueryOptions z_options;
            z_options.withscores = false;
            z_options.withattr = true;
            ValueDataArray values;
            if (options.in_members)
            {
                ZSetCache::GetRangeInZSetCache(subset, *hit, z_options.withscores, z_options.withattr,
                        ZSetValueStoreCallback, &values);
            }
            else
            {
                ZRangeByScoreRange(db, key, *hit, iter, z_options, true, ZSetValueStoreCallback, &values);
            }
            ValueDataArray::iterator vit = values.begin();
            while (vit != values.end())
            {
                GeoPoint point;
                vit->ToString(point.value);
                //attributes
                vit++;
                Buffer content(const_cast<char*>(vit->bytes_value.data()), 0, vit->bytes_value.size());
                if (point.Decode(content))
                {
                    if (GeoHashHelper::GetDistanceSquareIfInRadius(GEO_MERCATOR_TYPE, x, y, point.x, point.y,
                            options.radius, point.distance))
                    {
                        /*
                         * filter by exclude/include
                         */
                        if (!options.includes.empty() || !options.excludes.empty())
                        {
                            ValueData subst;
                            subst.SetValue(point.value, false);
                            bool matched = options.includes.empty() ? true : false;
                            if (!options.includes.empty())
                            {
                                StringStringMap::const_iterator sit = options.includes.begin();
                                while (sit != options.includes.end())
                                {
                                    ValueData mv;
                                    if (0 != MatchValueByPattern(db, sit->first, sit->second, subst, mv))
                                    {
                                        matched = false;
                                        break;
                                    }
                                    else
                                    {
                                        matched = true;
                                    }
                                    sit++;
                                }
                            }
                            if (matched && !options.excludes.empty())
                            {
                                StringStringMap::const_iterator sit = options.excludes.begin();
                                while (sit != options.excludes.end())
                                {
                                    ValueData mv;
                                    if (0 == MatchValueByPattern(db, sit->first, sit->second, subst, mv))
                                    {
                                        matched = false;
                                        break;
                                    }
                                    else
                                    {
                                        matched = true;
                                    }
                                    sit++;
                                }
                            }

                            if (matched)
                            {
                                points.push_back(point);
                            }
                        }
                        else
                        {
                            points.push_back(point);
                        }
                    }
                    else
                    {
                        //DEBUG_LOG("%s is not in radius:%.2fm", point.value.c_str(), options.radius);
                    }
                }
                else
                {
                    WARN_LOG("Failed to decode geo point.");
                }
                vit++;
            }
            hit++;
        }
        DELETE(iter);
        if (!options.nosort)
        {
            std::sort(points.begin(), points.end(), options.asc ? less_by_distance : great_by_distance);
        }

        if (options.offset > 0)
        {
            if ((uint32) options.offset > points.size())
            {
                points.clear();
            }
            else
            {
                GeoPointArray::iterator start = points.begin() + options.offset;
                points.erase(points.begin(), start);
            }
        }
        if (options.limit > 0)
        {
            if ((uint32) options.limit < points.size())
            {
                GeoPointArray::iterator end = points.begin() + options.limit;
                points.erase(end, points.end());
            }
        }
        GeoPointArray::iterator pit = points.begin();
        while (pit != points.end())
        {
            ValueData v;
            v.SetValue(pit->value, false);
            results.push_back(v);
            GeoGetOptionDeque::const_iterator ait = options.get_patterns.begin();
            while (ait != options.get_patterns.end())
            {
                ValueData attr;
                if (ait->get_distances)
                {
                    attr.SetDoubleValue(sqrt(pit->distance));
                    results.push_back(attr);
                }
                else if (ait->get_coodinates)
                {
                    if (options.coord_type == GEO_WGS84_TYPE)
                    {
                        pit->x = GeoHashHelper::GetWGS84X(pit->x);
                        pit->y = GeoHashHelper::GetWGS84Y(pit->y);
                    }
                    attr.SetDoubleValue(pit->x);
                    results.push_back(attr);
                    attr.SetDoubleValue(pit->y);
                    results.push_back(attr);
                }
                else if (ait->get_attr)
                {
                    StringStringMap::iterator found = pit->attrs.find(ait->get_pattern);
                    if (found != pit->attrs.end())
                    {
                        attr.SetValue(found->second, false);
                    }
                    results.push_back(attr);
                }
                else
                {
                    GetValueByPattern(db, ait->get_pattern, v, attr);
                    results.push_back(attr);
                }
                ait++;
            }
            pit++;
        }
        uint64 end_time = get_current_epoch_micros();
        DEBUG_LOG("Cost %llu microseconds to search.", end_time - start_time);
        return 0;
    }
}

<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/login/eula_view.h"

#include <signal.h>
#include <sys/types.h>
#include <string>

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/basictypes.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/customization_document.h"
#include "chrome/browser/chromeos/login/network_screen_delegate.h"
#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/views/dom_view.h"
#include "chrome/common/url_constants.h"
#include "chrome/installer/util/google_update_settings.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "views/controls/button/checkbox.h"
#include "views/controls/button/native_button.h"
#include "views/controls/label.h"
#include "views/grid_layout.h"
#include "views/layout_manager.h"
#include "views/standard_layout.h"

namespace {

const int kBorderSize = 10;
const int kMargin = 20;
const int kLastButtonHorizontalMargin = 10;
const int kCheckBowWidth = 22;
const int kTextMargin = 10;

// TODO(glotov): this URL should be changed to actual Google ChromeOS EULA.
// See crbug.com/4647
const char kGoogleEulaUrl[] = "about:terms";

enum kLayoutColumnsets {
  SINGLE_CONTROL_ROW,
  SINGLE_CONTROL_WITH_SHIFT_ROW,
  SINGLE_LINK_WITH_SHIFT_ROW,
  LAST_ROW
};

// A simple LayoutManager that causes the associated view's one child to be
// sized to match the bounds of its parent except the bounds, if set.
struct FillLayoutWithBorder : public views::LayoutManager {
  // Overridden from LayoutManager:
  virtual void Layout(views::View* host) {
    DCHECK(host->GetChildViewCount());
    host->GetChildViewAt(0)->SetBounds(host->GetLocalBounds(false));
  }
  virtual gfx::Size GetPreferredSize(views::View* host) {
    return gfx::Size(host->width(), host->height());
  }
};

}  // namespace

namespace chromeos {

EulaView::EulaView(chromeos::ScreenObserver* observer)
    : google_eula_label_(NULL),
      google_eula_view_(NULL),
      usage_statistics_checkbox_(NULL),
      learn_more_link_(NULL),
      oem_eula_label_(NULL),
      oem_eula_view_(NULL),
      system_security_settings_link_(NULL),
      cancel_button_(NULL),
      continue_button_(NULL),
      observer_(observer) {
}

EulaView::~EulaView() {
}

// Convenience function to set layout's columnsets for this screen.
static void SetUpGridLayout(views::GridLayout* layout) {
  static const int kPadding = kBorderSize + kMargin;
  views::ColumnSet* column_set = layout->AddColumnSet(SINGLE_CONTROL_ROW);
  column_set->AddPaddingColumn(0, kPadding);
  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, kPadding);

  column_set = layout->AddColumnSet(SINGLE_CONTROL_WITH_SHIFT_ROW);
  column_set->AddPaddingColumn(0, kPadding + kTextMargin);
  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, kPadding);

  column_set = layout->AddColumnSet(SINGLE_LINK_WITH_SHIFT_ROW);
  column_set->AddPaddingColumn(0, kPadding + kTextMargin + kCheckBowWidth);
  column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, kPadding);

  column_set = layout->AddColumnSet(LAST_ROW);
  column_set->AddPaddingColumn(0, kPadding + kTextMargin);
  column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, 0);
  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
                        views::GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
                        views::GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, kLastButtonHorizontalMargin + kBorderSize);
}

// Convenience function. Returns URL of the OEM EULA page that should be
// displayed using current locale and manifest. Returns empty URL otherwise.
static GURL GetOemEulaPagePath() {
  const StartupCustomizationDocument *customization =
      WizardController::default_controller()->GetCustomization();
  if (customization) {
    std::string locale = g_browser_process->GetApplicationLocale();
    FilePath eula_page_path = customization->GetEULAPagePath(locale);
    if (eula_page_path.empty()) {
      LOG(INFO) << "No eula found for locale: " << locale;
      locale = customization->initial_locale();
      eula_page_path = customization->GetEULAPagePath(locale);
    }
    if (!eula_page_path.empty()) {
      const std::string page_path = std::string(chrome::kFileScheme) +
          chrome::kStandardSchemeSeparator + eula_page_path.value();
      return GURL(page_path);
    } else {
      LOG(INFO) << "No eula found for locale: " << locale;
    }
  } else {
    LOG(ERROR) << "No manifest found.";
  }
  return GURL();
}

void EulaView::Init() {
  // Use rounded rect background.
  views::Painter* painter = CreateWizardPainter(
      &BorderDefinition::kScreenBorder);
  set_background(
      views::Background::CreateBackgroundPainter(true, painter));

  // Layout created controls.
  views::GridLayout* layout = new views::GridLayout(this);
  SetLayoutManager(layout);
  SetUpGridLayout(layout);

  static const int kPadding = kBorderSize + kMargin;
  layout->AddPaddingRow(0, kPadding);
  layout->StartRow(0, SINGLE_CONTROL_ROW);
  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
  gfx::Font label_font =
      rb.GetFont(ResourceBundle::MediumFont).DeriveFont(0, gfx::Font::NORMAL);
  google_eula_label_ = new views::Label(std::wstring(), label_font);
  layout->AddView(google_eula_label_, 1, 1,
                  views::GridLayout::LEADING, views::GridLayout::FILL);

  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
  layout->StartRow(1, SINGLE_CONTROL_ROW);
  views::View* box_view = new views::View();
  box_view->set_border(views::Border::CreateSolidBorder(1, SK_ColorBLACK));
  box_view->SetLayoutManager(new FillLayoutWithBorder());
  layout->AddView(box_view);

  google_eula_view_ = new DOMView();
  box_view->AddChildView(google_eula_view_);

  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
  layout->StartRow(0, SINGLE_CONTROL_WITH_SHIFT_ROW);
  usage_statistics_checkbox_ = new views::Checkbox();
  usage_statistics_checkbox_->SetMultiLine(true);
  usage_statistics_checkbox_->SetChecked(
      GoogleUpdateSettings::GetCollectStatsConsent());
  layout->AddView(usage_statistics_checkbox_);

  layout->StartRow(0, SINGLE_LINK_WITH_SHIFT_ROW);
  learn_more_link_ = new views::Link();
  learn_more_link_->SetController(this);
  layout->AddView(learn_more_link_);

  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
  layout->StartRow(0, SINGLE_CONTROL_ROW);
  oem_eula_label_ = new views::Label(std::wstring(), label_font);
  layout->AddView(oem_eula_label_, 1, 1,
                  views::GridLayout::LEADING, views::GridLayout::FILL);

  oem_eula_page_ = GetOemEulaPagePath();
  if (!oem_eula_page_.is_empty()) {
    layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
    layout->StartRow(1, SINGLE_CONTROL_ROW);
    box_view = new views::View();
    box_view->SetLayoutManager(new FillLayoutWithBorder());
    box_view->set_border(views::Border::CreateSolidBorder(1, SK_ColorBLACK));
    layout->AddView(box_view);

    oem_eula_view_ = new DOMView();
    box_view->AddChildView(oem_eula_view_);
  }

  layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
  layout->StartRow(0, LAST_ROW);
  system_security_settings_link_ = new views::Link();
  system_security_settings_link_->SetController(this);
  layout->AddView(system_security_settings_link_);

  cancel_button_ = new views::NativeButton(this, std::wstring());
  cancel_button_->SetEnabled(false);
  layout->AddView(cancel_button_);

  continue_button_ = new views::NativeButton(this, std::wstring());
  layout->AddView(continue_button_);
  layout->AddPaddingRow(0, kPadding);

  UpdateLocalizedStrings();
}

void EulaView::LoadEulaView(DOMView* eula_view,
                            views::Label* eula_label,
                            const GURL& eula_url) {
  Profile* profile = ProfileManager::GetDefaultProfile();
  eula_view->Init(profile,
                  SiteInstance::CreateSiteInstanceForURL(profile, eula_url));
  eula_view->LoadURL(eula_url);
  eula_view->tab_contents()->set_delegate(this);
}

void EulaView::UpdateLocalizedStrings() {
  // Load Google EULA and its title.
  LoadEulaView(google_eula_view_, google_eula_label_, GURL(kGoogleEulaUrl));

  // Load OEM EULA and its title.
  if (!oem_eula_page_.is_empty())
    LoadEulaView(oem_eula_view_, oem_eula_label_, oem_eula_page_);

  // Load other labels from resources.
  usage_statistics_checkbox_->SetLabel(
      l10n_util::GetString(IDS_EULA_CHECKBOX_ENABLE_LOGGING));
  learn_more_link_->SetText(
      l10n_util::GetString(IDS_LEARN_MORE));
  system_security_settings_link_->SetText(
      l10n_util::GetString(IDS_EULA_SYSTEM_SECURITY_SETTINGS_LINK));
  continue_button_->SetLabel(
      l10n_util::GetString(IDS_EULA_ACCEPT_AND_CONTINUE_BUTTON));
  cancel_button_->SetLabel(
      l10n_util::GetString(IDS_CANCEL));
}

////////////////////////////////////////////////////////////////////////////////
// views::View: implementation:

void EulaView::OnLocaleChanged() {
  UpdateLocalizedStrings();
  Layout();
}

////////////////////////////////////////////////////////////////////////////////
// views::ButtonListener implementation:

void EulaView::ButtonPressed(views::Button* sender, const views::Event& event) {
  if (sender == continue_button_) {
    if (usage_statistics_checkbox_) {
      GoogleUpdateSettings::SetCollectStatsConsent(
        usage_statistics_checkbox_->checked());
    }
    observer_->OnExit(ScreenObserver::EULA_ACCEPTED);
  }
  // TODO(glotov): handle cancel button.
}

////////////////////////////////////////////////////////////////////////////////
// views::LinkController implementation:

void EulaView::LinkActivated(views::Link* source, int event_flags) {
  // TODO(glotov): handle link clicks.
}

////////////////////////////////////////////////////////////////////////////////
// TabContentsDelegate implementation:

// Convenience function. Queries |eula_view| for HTML title and, if it
// is ready, assigns it to |eula_label| and returns true so the caller
// view calls Layout().
static bool PublishTitleIfReady(const TabContents* contents,
                                DOMView* eula_view,
                                views::Label* eula_label) {
  if (contents != eula_view->tab_contents())
    return false;
  eula_label->SetText(UTF16ToWide(eula_view->tab_contents()->GetTitle()));
  return true;
}

void EulaView::NavigationStateChanged(const TabContents* contents,
                                      unsigned changed_flags) {
  if (changed_flags & TabContents::INVALIDATE_TITLE) {
    if (PublishTitleIfReady(contents, google_eula_view_, google_eula_label_) ||
        PublishTitleIfReady(contents, oem_eula_view_, oem_eula_label_)) {
      Layout();
    }
  }
}

}  // namespace chromeos
<commit_msg>EULA screen enabling/disabling crash/metrics reporting renovated.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/login/eula_view.h"

#include <signal.h>
#include <sys/types.h>
#include <string>

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/basictypes.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/customization_document.h"
#include "chrome/browser/chromeos/login/network_screen_delegate.h"
#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/options_util.h"
#include "chrome/browser/pref_service.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/views/dom_view.h"
#include "chrome/common/url_constants.h"
#include "chrome/installer/util/google_update_settings.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "views/controls/button/checkbox.h"
#include "views/controls/button/native_button.h"
#include "views/controls/label.h"
#include "views/grid_layout.h"
#include "views/layout_manager.h"
#include "views/standard_layout.h"

#if defined(USE_LINUX_BREAKPAD)
#include "chrome/app/breakpad_linux.h"
#endif

namespace {

const int kBorderSize = 10;
const int kMargin = 20;
const int kLastButtonHorizontalMargin = 10;
const int kCheckBowWidth = 22;
const int kTextMargin = 10;

// TODO(glotov): this URL should be changed to actual Google ChromeOS EULA.
// See crbug.com/4647
const char kGoogleEulaUrl[] = "about:terms";

enum kLayoutColumnsets {
  SINGLE_CONTROL_ROW,
  SINGLE_CONTROL_WITH_SHIFT_ROW,
  SINGLE_LINK_WITH_SHIFT_ROW,
  LAST_ROW
};

// A simple LayoutManager that causes the associated view's one child to be
// sized to match the bounds of its parent except the bounds, if set.
struct FillLayoutWithBorder : public views::LayoutManager {
  // Overridden from LayoutManager:
  virtual void Layout(views::View* host) {
    DCHECK(host->GetChildViewCount());
    host->GetChildViewAt(0)->SetBounds(host->GetLocalBounds(false));
  }
  virtual gfx::Size GetPreferredSize(views::View* host) {
    return gfx::Size(host->width(), host->height());
  }
};

}  // namespace

namespace chromeos {

EulaView::EulaView(chromeos::ScreenObserver* observer)
    : google_eula_label_(NULL),
      google_eula_view_(NULL),
      usage_statistics_checkbox_(NULL),
      learn_more_link_(NULL),
      oem_eula_label_(NULL),
      oem_eula_view_(NULL),
      system_security_settings_link_(NULL),
      cancel_button_(NULL),
      continue_button_(NULL),
      observer_(observer) {
}

EulaView::~EulaView() {
}

// Convenience function to set layout's columnsets for this screen.
static void SetUpGridLayout(views::GridLayout* layout) {
  static const int kPadding = kBorderSize + kMargin;
  views::ColumnSet* column_set = layout->AddColumnSet(SINGLE_CONTROL_ROW);
  column_set->AddPaddingColumn(0, kPadding);
  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, kPadding);

  column_set = layout->AddColumnSet(SINGLE_CONTROL_WITH_SHIFT_ROW);
  column_set->AddPaddingColumn(0, kPadding + kTextMargin);
  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, kPadding);

  column_set = layout->AddColumnSet(SINGLE_LINK_WITH_SHIFT_ROW);
  column_set->AddPaddingColumn(0, kPadding + kTextMargin + kCheckBowWidth);
  column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, kPadding);

  column_set = layout->AddColumnSet(LAST_ROW);
  column_set->AddPaddingColumn(0, kPadding + kTextMargin);
  column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, 0);
  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
                        views::GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
                        views::GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, kLastButtonHorizontalMargin + kBorderSize);
}

// Convenience function. Returns URL of the OEM EULA page that should be
// displayed using current locale and manifest. Returns empty URL otherwise.
static GURL GetOemEulaPagePath() {
  const StartupCustomizationDocument *customization =
      WizardController::default_controller()->GetCustomization();
  if (customization) {
    std::string locale = g_browser_process->GetApplicationLocale();
    FilePath eula_page_path = customization->GetEULAPagePath(locale);
    if (eula_page_path.empty()) {
      LOG(INFO) << "No eula found for locale: " << locale;
      locale = customization->initial_locale();
      eula_page_path = customization->GetEULAPagePath(locale);
    }
    if (!eula_page_path.empty()) {
      const std::string page_path = std::string(chrome::kFileScheme) +
          chrome::kStandardSchemeSeparator + eula_page_path.value();
      return GURL(page_path);
    } else {
      LOG(INFO) << "No eula found for locale: " << locale;
    }
  } else {
    LOG(ERROR) << "No manifest found.";
  }
  return GURL();
}

void EulaView::Init() {
  // Use rounded rect background.
  views::Painter* painter = CreateWizardPainter(
      &BorderDefinition::kScreenBorder);
  set_background(
      views::Background::CreateBackgroundPainter(true, painter));

  // Layout created controls.
  views::GridLayout* layout = new views::GridLayout(this);
  SetLayoutManager(layout);
  SetUpGridLayout(layout);

  static const int kPadding = kBorderSize + kMargin;
  layout->AddPaddingRow(0, kPadding);
  layout->StartRow(0, SINGLE_CONTROL_ROW);
  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
  gfx::Font label_font =
      rb.GetFont(ResourceBundle::MediumFont).DeriveFont(0, gfx::Font::NORMAL);
  google_eula_label_ = new views::Label(std::wstring(), label_font);
  layout->AddView(google_eula_label_, 1, 1,
                  views::GridLayout::LEADING, views::GridLayout::FILL);

  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
  layout->StartRow(1, SINGLE_CONTROL_ROW);
  views::View* box_view = new views::View();
  box_view->set_border(views::Border::CreateSolidBorder(1, SK_ColorBLACK));
  box_view->SetLayoutManager(new FillLayoutWithBorder());
  layout->AddView(box_view);

  google_eula_view_ = new DOMView();
  box_view->AddChildView(google_eula_view_);

  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
  layout->StartRow(0, SINGLE_CONTROL_WITH_SHIFT_ROW);
  usage_statistics_checkbox_ = new views::Checkbox();
  usage_statistics_checkbox_->SetMultiLine(true);
  usage_statistics_checkbox_->SetChecked(
      g_browser_process->local_state()->GetBoolean(
          prefs::kMetricsReportingEnabled));
  layout->AddView(usage_statistics_checkbox_);

  layout->StartRow(0, SINGLE_LINK_WITH_SHIFT_ROW);
  learn_more_link_ = new views::Link();
  learn_more_link_->SetController(this);
  layout->AddView(learn_more_link_);

  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
  layout->StartRow(0, SINGLE_CONTROL_ROW);
  oem_eula_label_ = new views::Label(std::wstring(), label_font);
  layout->AddView(oem_eula_label_, 1, 1,
                  views::GridLayout::LEADING, views::GridLayout::FILL);

  oem_eula_page_ = GetOemEulaPagePath();
  if (!oem_eula_page_.is_empty()) {
    layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
    layout->StartRow(1, SINGLE_CONTROL_ROW);
    box_view = new views::View();
    box_view->SetLayoutManager(new FillLayoutWithBorder());
    box_view->set_border(views::Border::CreateSolidBorder(1, SK_ColorBLACK));
    layout->AddView(box_view);

    oem_eula_view_ = new DOMView();
    box_view->AddChildView(oem_eula_view_);
  }

  layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
  layout->StartRow(0, LAST_ROW);
  system_security_settings_link_ = new views::Link();
  system_security_settings_link_->SetController(this);
  layout->AddView(system_security_settings_link_);

  cancel_button_ = new views::NativeButton(this, std::wstring());
  cancel_button_->SetEnabled(false);
  layout->AddView(cancel_button_);

  continue_button_ = new views::NativeButton(this, std::wstring());
  layout->AddView(continue_button_);
  layout->AddPaddingRow(0, kPadding);

  UpdateLocalizedStrings();
}

void EulaView::LoadEulaView(DOMView* eula_view,
                            views::Label* eula_label,
                            const GURL& eula_url) {
  Profile* profile = ProfileManager::GetDefaultProfile();
  eula_view->Init(profile,
                  SiteInstance::CreateSiteInstanceForURL(profile, eula_url));
  eula_view->LoadURL(eula_url);
  eula_view->tab_contents()->set_delegate(this);
}

void EulaView::UpdateLocalizedStrings() {
  // Load Google EULA and its title.
  LoadEulaView(google_eula_view_, google_eula_label_, GURL(kGoogleEulaUrl));

  // Load OEM EULA and its title.
  if (!oem_eula_page_.is_empty())
    LoadEulaView(oem_eula_view_, oem_eula_label_, oem_eula_page_);

  // Load other labels from resources.
  usage_statistics_checkbox_->SetLabel(
      l10n_util::GetString(IDS_EULA_CHECKBOX_ENABLE_LOGGING));
  learn_more_link_->SetText(
      l10n_util::GetString(IDS_LEARN_MORE));
  system_security_settings_link_->SetText(
      l10n_util::GetString(IDS_EULA_SYSTEM_SECURITY_SETTINGS_LINK));
  continue_button_->SetLabel(
      l10n_util::GetString(IDS_EULA_ACCEPT_AND_CONTINUE_BUTTON));
  cancel_button_->SetLabel(
      l10n_util::GetString(IDS_CANCEL));
}

////////////////////////////////////////////////////////////////////////////////
// views::View: implementation:

void EulaView::OnLocaleChanged() {
  UpdateLocalizedStrings();
  Layout();
}

////////////////////////////////////////////////////////////////////////////////
// views::ButtonListener implementation:

void EulaView::ButtonPressed(views::Button* sender, const views::Event& event) {
  if (sender == continue_button_) {
    if (usage_statistics_checkbox_) {
      const bool enable_reporting = usage_statistics_checkbox_->checked();
      PrefService* prefs = g_browser_process->local_state();
      if (prefs->GetBoolean(prefs::kMetricsReportingEnabled) !=
          enable_reporting) {
        prefs->SetBoolean(prefs::kMetricsReportingEnabled, enable_reporting);
        prefs->SavePersistentPrefs();
        OptionsUtil::ResolveMetricsReportingEnabled(enable_reporting);
#if defined(USE_LINUX_BREAKPAD)
        if (enable_reporting)
          InitCrashReporter();
#endif
      }
    }
    observer_->OnExit(ScreenObserver::EULA_ACCEPTED);
  }
  // TODO(glotov): handle cancel button.
}

////////////////////////////////////////////////////////////////////////////////
// views::LinkController implementation:

void EulaView::LinkActivated(views::Link* source, int event_flags) {
  // TODO(glotov): handle link clicks.
}

////////////////////////////////////////////////////////////////////////////////
// TabContentsDelegate implementation:

// Convenience function. Queries |eula_view| for HTML title and, if it
// is ready, assigns it to |eula_label| and returns true so the caller
// view calls Layout().
static bool PublishTitleIfReady(const TabContents* contents,
                                DOMView* eula_view,
                                views::Label* eula_label) {
  if (contents != eula_view->tab_contents())
    return false;
  eula_label->SetText(UTF16ToWide(eula_view->tab_contents()->GetTitle()));
  return true;
}

void EulaView::NavigationStateChanged(const TabContents* contents,
                                      unsigned changed_flags) {
  if (changed_flags & TabContents::INVALIDATE_TITLE) {
    if (PublishTitleIfReady(contents, google_eula_view_, google_eula_label_) ||
        PublishTitleIfReady(contents, oem_eula_view_, oem_eula_label_)) {
      Layout();
    }
  }
}

}  // namespace chromeos
<|endoftext|>