<commit_before>/*  Copyright (c) MediaArea.net SARL. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license that can
 *  be found in the License.html file in the root of the source tree.
 */

//---------------------------------------------------------------------------
// Pre-compilation
#include "MediaInfo/PreComp.h"
#ifdef __BORLANDC__
    #pragma hdrstop
#endif
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#include "MediaInfo/Setup.h"
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#if defined(MEDIAINFO_OTHERTEXT_YES)
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#include "MediaInfo/Text/File_OtherText.h"
//---------------------------------------------------------------------------

namespace MediaInfoLib
{

//***************************************************************************
// Functions
//***************************************************************************

void File_OtherText::Read_Buffer_Continue()
{
    if (Buffer_Size<0x200)
    {
        Element_WaitForMoreData();
        return;
    }

    Element_Offset=File_Size-(File_Offset+Buffer_Offset);

    Ztring Format, FormatMore, Codec;
    Ztring File;
    ZtringList Lines;

    //Feed File and Lines
    File.From_UTF8((const char*)Buffer, Buffer_Size>65536?65536:Buffer_Size);
    if (File.empty())
        File.From_Local((const char*)Buffer, Buffer_Size>65536?65536:Buffer_Size); // Trying from local code page
    if (File.size()<0x100)
    {
        File.From_Unicode((wchar_t*)Buffer, 0, Buffer_Size/sizeof(wchar_t)); //Unicode with BOM
        //TODO: Order of bytes (big or Little endian)
        if (File.size()<0x100)
        {
            Reject("Other text");
            return;
        }
    }
    if (File.size()>0x1000)
        File.resize(0x1000); //Do not work on too big
    File.FindAndReplace(__T("\r\n"), __T("\n"), 0, Ztring_Recursive);
    File.FindAndReplace(__T("\r"), __T("\n"), 0, Ztring_Recursive);
    Lines.Separator_Set(0, __T("\n"));
    Lines.Write(File);
    Lines.resize(0x20);

         if (Lines[0]==__T("[Script Info]")
          && (Lines.Find(__T("ScriptType: v4.00"))!=Error || Lines.Find(__T("Script Type: V4.00"))!=Error)
          && Lines.Find(__T("[V4 Styles]"))!=Error
          )
    {
       Format=__T("SSA");
       FormatMore=__T("SubStation Alpha");
       Codec=__T("SSA");
    }
    else if (Lines[0]==__T("[Script Info]")
          && (Lines.Find(__T("ScriptType: v4.00+"))!=Error || Lines.Find(__T("Script Type: V4.00+"))!=Error)
          && Lines.Find(__T("[V4+ Styles]"))!=Error
          )
    {
       Format=__T("ASS");
       FormatMore=__T("Advanced SubStation Alpha");
       Codec=__T("ASS");
    }
    else if (Lines[0].size()>24
          && Lines[0][ 0]==__T('0') && Lines[0][ 1]==__T('0')
          && Lines[0][ 2]==__T(':') && Lines[0][ 5]==__T(':') && Lines[0][ 8]==__T(':')
          && Lines[0][11]==__T(' ')
          && Lines[0][12]==__T('0') && Lines[0][13]==__T('0')
          && Lines[0][14]==__T(':') && Lines[0][17]==__T(':') && Lines[0][20]==__T(':')
          && Lines[0][23]==__T(' ')
          )
    {
       Format=__T("Adobe encore DVD");
       Codec=__T("Adobe");
    }
    else if (Lines[0].size()==11
          && Lines[0][0]==__T('-') && Lines[0][1]==__T('-') && Lines[0][2]==__T('>') && Lines[0][3]==__T('>') && Lines[0][4]==__T(' ')
          && Lines[0][5]==__T('0')
          && Lines[1].empty()!=true
          )
    {
       Format=__T("AQTitle");
       Codec=__T("AQTitle");
    }
    else if (Lines[0].size()>28
          && Lines[0][ 0]==__T('0') && Lines[0][ 1]==__T('0')
          && Lines[0][ 2]==__T(':') && Lines[0][ 5]==__T(':') && Lines[0][ 8]==__T(':')
          && Lines[0][11]==__T(' ') && Lines[0][12]==__T(',') && Lines[0][13]==__T(' ')
          && Lines[0][14]==__T('0') && Lines[0][15]==__T('0')
          && Lines[0][16]==__T(':') && Lines[0][19]==__T(':') && Lines[0][22]==__T(':')
          && Lines[0][25]==__T(' ') && Lines[0][16]==__T(',') && Lines[0][27]==__T(' ')
          )
    {
       Format=__T("Captions 32");
       Codec=__T("Caption 32");
    }
    else if (Lines[0].size()==23
          && Lines[0]==__T("*Timecode type: PAL/EBU")
          && Lines[1].empty()
          && Lines[2].size()==23
          && Lines[2][ 0]==__T('0') && Lines[2][ 1]==__T('0')
          && Lines[2][ 2]==__T(':') && Lines[2][ 5]==__T(':') && Lines[2][ 8]==__T(':')
          && Lines[2][11]==__T(' ')
          && Lines[2][12]==__T('0') && Lines[2][13]==__T('0')
          && Lines[2][14]==__T(':') && Lines[2][17]==__T(':') && Lines[2][20]==__T(':')
          && Lines[2].size()>0
          )
    {
       Format=__T("Captions Inc");
       Codec=__T("Captions inc");
    }
    else if (Lines[0].size()>1
          && Lines[0][0]==__T('*')
          && Lines.Find(__T("** Caption Number 1"))!=Error
    )
    {
       Format=__T("Cheeta");
    }
    else if (Lines[0].size()>10
          && Lines[0][0]==__T('~') && Lines[0][1]==__T('C') && Lines[0][2]==__T('P') && Lines[0][3]==__T('C') && Lines[0][9]==__T('~')
          && Lines[1][ 0]==__T('0') && Lines[1][ 1]==__T('0')
          && Lines[1][ 2]==__T(':') && Lines[1][ 5]==__T(':') && Lines[1][ 8]==__T(':')
    )
    {
       Format=__T("CPC Captioning");
       Codec=__T("CPC Captioning");
    }
    else if (Lines[0].find(__T("<SAMI>"))==0)
    {
       Format=__T("SAMI");
    }
    else
        return;

    if (Format.empty())
        return;

    Accept("Other text");

    if (!IsSub)
    {
        Fill(Stream_General, 0, General_Format, Format);
        Fill(Stream_General, 0, General_Format_Info, FormatMore, true);
    }

    Stream_Prepare(Stream_Text);
    Fill(Stream_Text, 0, Text_Format, Format);
    Fill(Stream_Text, 0, Text_Codec, Codec);

    //No more need data
    Element_Begin1(Format);
    Element_End0();
    Finish("Other text");
}

} //NameSpace

#endif
<commit_msg>Small opt File_OtherText::Read_Buffer_Continue<commit_after>/*  Copyright (c) MediaArea.net SARL. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license that can
 *  be found in the License.html file in the root of the source tree.
 */

//---------------------------------------------------------------------------
// Pre-compilation
#include "MediaInfo/PreComp.h"
#ifdef __BORLANDC__
    #pragma hdrstop
#endif
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#include "MediaInfo/Setup.h"
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#if defined(MEDIAINFO_OTHERTEXT_YES)
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#include "MediaInfo/Text/File_OtherText.h"
//---------------------------------------------------------------------------

namespace MediaInfoLib
{

//***************************************************************************
// Functions
//***************************************************************************

void File_OtherText::Read_Buffer_Continue()
{
    if (Buffer_Size<0x200)
    {
        Element_WaitForMoreData();
        return;
    }

    Element_Offset=File_Size-(File_Offset+Buffer_Offset);

    Ztring Format, FormatMore, Codec;
    Ztring File;
    ZtringList Lines;

    //Feed File and Lines
    File.From_UTF8((const char*)Buffer, Buffer_Size>65536?65536:Buffer_Size);
    if (File.empty())
        File.From_Local((const char*)Buffer, Buffer_Size>65536?65536:Buffer_Size); // Trying from local code page
    if (File.size()<0x100)
    {
        File.From_Unicode((wchar_t*)Buffer, 0, Buffer_Size/sizeof(wchar_t)); //Unicode with BOM
        //TODO: Order of bytes (big or Little endian)
        if (File.size()<0x100)
        {
            Reject("Other text");
            return;
        }
    }
    if (File.size()>0x1000)
        File.resize(0x1000); //Do not work on too big
    File.FindAndReplace(__T("\r\n"), __T("\n"), 0, Ztring_Recursive);
    File.FindAndReplace(__T("\r"), __T("\n"), 0, Ztring_Recursive);
    Lines.Separator_Set(0, __T("\n"));
    Lines.Write(File);
    Lines.resize(0x20);
	const bool Is_Script_Info = Lines[0] == __T("[Script Info]");
         if (Is_Script_Info
          && (Lines.Find(__T("ScriptType: v4.00"))!=Error || Lines.Find(__T("Script Type: V4.00"))!=Error)
          && Lines.Find(__T("[V4 Styles]"))!=Error
          )
    {
       Format=__T("SSA");
       FormatMore=__T("SubStation Alpha");
       Codec=Format;
    }
    else if (Is_Script_Info
          && (Lines.Find(__T("ScriptType: v4.00+"))!=Error || Lines.Find(__T("Script Type: V4.00+"))!=Error)
          && Lines.Find(__T("[V4+ Styles]"))!=Error
          )
    {
       Format=__T("ASS");
       FormatMore=__T("Advanced SubStation Alpha");
       Codec=__T("ASS");
    }
    else if (Lines[0].size()>24
          && Lines[0][ 0]==__T('0') && Lines[0][ 1]==__T('0')
          && Lines[0][ 2]==__T(':') && Lines[0][ 5]==__T(':') && Lines[0][ 8]==__T(':')
          && Lines[0][11]==__T(' ')
          && Lines[0][12]==__T('0') && Lines[0][13]==__T('0')
          && Lines[0][14]==__T(':') && Lines[0][17]==__T(':') && Lines[0][20]==__T(':')
          && Lines[0][23]==__T(' ')
          )
    {
       Format=__T("Adobe encore DVD");
       Codec=__T("Adobe");
    }
    else if (Lines[0].size()==11
          && Lines[0][0]==__T('-') && Lines[0][1]==__T('-') && Lines[0][2]==__T('>') && Lines[0][3]==__T('>') && Lines[0][4]==__T(' ')
          && Lines[0][5]==__T('0')
          && Lines[1].empty()!=true
          )
    {
       Format=__T("AQTitle");
       Codec=Format;
    }
    else if (Lines[0].size()>28
          && Lines[0][ 0]==__T('0') && Lines[0][ 1]==__T('0')
          && Lines[0][ 2]==__T(':') && Lines[0][ 5]==__T(':') && Lines[0][ 8]==__T(':')
          && Lines[0][11]==__T(' ') && Lines[0][12]==__T(',') && Lines[0][13]==__T(' ')
          && Lines[0][14]==__T('0') && Lines[0][15]==__T('0')
          && Lines[0][16]==__T(':') && Lines[0][19]==__T(':') && Lines[0][22]==__T(':')
          && Lines[0][25]==__T(' ') && Lines[0][16]==__T(',') && Lines[0][27]==__T(' ')
          )
    {
       Format=__T("Captions 32");
       Codec=__T("Caption 32");
    }
    else if (Lines[0].size()==23
          && Lines[0]==__T("*Timecode type: PAL/EBU")
          && Lines[1].empty()
          && Lines[2].size()==23
          && Lines[2][ 0]==__T('0') && Lines[2][ 1]==__T('0')
          && Lines[2][ 2]==__T(':') && Lines[2][ 5]==__T(':') && Lines[2][ 8]==__T(':')
          && Lines[2][11]==__T(' ')
          && Lines[2][12]==__T('0') && Lines[2][13]==__T('0')
          && Lines[2][14]==__T(':') && Lines[2][17]==__T(':') && Lines[2][20]==__T(':')
          && Lines[2].size()>0
          )
    {
       Format=__T("Captions Inc");
       Codec=Format;
    }
    else if (Lines[0].size()>1
          && Lines[0][0]==__T('*')
          && Lines.Find(__T("** Caption Number 1"))!=Error
    )
    {
       Format=__T("Cheeta");
    }
    else if (Lines[0].size()>10
          && Lines[0][0]==__T('~') && Lines[0][1]==__T('C') && Lines[0][2]==__T('P') && Lines[0][3]==__T('C') && Lines[0][9]==__T('~')
          && Lines[1][ 0]==__T('0') && Lines[1][ 1]==__T('0')
          && Lines[1][ 2]==__T(':') && Lines[1][ 5]==__T(':') && Lines[1][ 8]==__T(':')
    )
    {
       Format=__T("CPC Captioning");
       Codec=Format;
    }
    else if (Lines[0].find(__T("<SAMI>"))==0)
    {
       Format=__T("SAMI");
    }
    else
        return;

    if (Format.empty())
        return;

    Accept("Other text");

    if (!IsSub)
    {
        Fill(Stream_General, 0, General_Format, Format);
        Fill(Stream_General, 0, General_Format_Info, FormatMore, true);
    }

    Stream_Prepare(Stream_Text);
    Fill(Stream_Text, 0, Text_Format, Format);
    Fill(Stream_Text, 0, Text_Codec, Codec);

    //No more need data
    Element_Begin1(Format);
    Element_End0();
    Finish("Other text");
}

} //NameSpace

#endif
<|endoftext|>


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

#include <pangolin/platform.h>

#include <pangolin/utils/file_utils.h>

#ifdef _WIN_
#  define WIN32_LEAN_AND_MEAN
#  include <Windows.h>
#  include <Shlobj.h>
#else
#  include <dirent.h>
#  include <sys/types.h>
#  include <sys/stat.h>
#  include <sys/signal.h>
#  include <stdio.h>
#  include <string.h>
#  include <unistd.h>
#  include <fcntl.h>
#  include <errno.h>
#  include <poll.h>
#endif // _WIN_

#include <algorithm>
#include <sstream>
#include <list>

namespace pangolin
{

std::vector<std::string>& Split(const std::string& s, char delim, std::vector<std::string>& elements) {
    std::stringstream ss(s);
    std::string item;
    while (std::getline(ss, item, delim)) {
        elements.push_back(item);
    }
    return elements;
}

std::vector<std::string> Split(const std::string &s, char delim) {
    std::vector<std::string> elems;
    return Split(s, delim, elems);
}

std::vector<std::string> Expand(const std::string &s, char open, char close, char delim)
{
    const size_t no = s.find_first_of(open);
    if(no != std::string::npos) {
        const size_t nc = s.find_first_of(close, no);
        if(no != std::string::npos) {
            const std::string pre  = s.substr(0, no);
            const std::string mid  = s.substr(no+1, nc-no-1);
            const std::string post = s.substr(nc+1, std::string::npos);
            const std::vector<std::string> options = Split(mid, delim);
            std::vector<std::string> expansion;

            for(std::vector<std::string>::const_iterator iop = options.begin(); iop != options.end(); ++iop)
            {
                std::string full = pre + *iop + post;
                expansion.push_back(full);
            }
            return expansion;
        }
        // Open but no close is unusual. Leave it for caller to see if valid
    }

    std::vector<std::string> ret;
    ret.push_back(s);
    return ret;
}

// Make path seperator consistent for OS.
void PathOsNormaliseInplace(std::string& path)
{
#ifdef _WIN_
    std::replace(path.begin(), path.end(), '/', '\\');
#else
    std::replace(path.begin(), path.end(), '\\', '/');
#endif
}

std::string SanitizePath(const std::string& path)
{
    std::string path_copy(path.length(), '\0');

    int p_slash1 = -1;
    int p_slash0 = -1;
    int n_dots = 0;

    int dst = 0;
    for(int src=0; src < (int)path.length(); ++src) {
        if(path[src] == '/') {
            if(n_dots==1 && p_slash0 >=0) {
                dst = p_slash0;
                for(p_slash1=p_slash0-1; p_slash1>=0 && path_copy[p_slash1] != '/'; --p_slash1);
            }else if(n_dots==2) {
                if(p_slash1 >=0) {
                    dst = p_slash1;
                    p_slash0 = dst;
                    for(p_slash1=p_slash0-1; p_slash1>=0 && path_copy[p_slash1] != '/'; --p_slash1) {
                        if( path_copy[p_slash1] == '.' ) {
                            p_slash1=-1;
                            break;
                        }
                    }
                }else{
                    p_slash1 = -1;
                    p_slash0 = dst;
                }
            }else{
                p_slash1 = p_slash0;
                p_slash0 = dst;
            }
            n_dots = 0;
        }else if(path[src] == '.' ){
            if((dst-p_slash0) == n_dots+1) {
                ++n_dots;
            }
        }else{
            n_dots = 0;
        }
        path_copy[dst++] = path[src];
    }

    return path_copy.substr(0,dst);
}

// Return path 'levels' directories above 'path'
std::string PathParent(const std::string& path, int levels)
{
    std::string res = path;

    while (levels > 0) {
        if (res.length() == 0) {
            res = std::string();
            for (int l = 0; l < levels; ++l) {
#ifdef _WIN_
                res += std::string("..\\");
#else
                res += std::string("../");
#endif
            }
            return res;
        }else{
            const size_t nLastSlash = res.find_last_of("/\\");

            if (nLastSlash != std::string::npos) {
                res = path.substr(0, nLastSlash);
            } else{
                res = std::string();
            }

            --levels;
        }
    }

    return res;
}

std::string FindPath(const std::string& child_path, const std::string& signature_path)
{
    std::string path = child_path;
    std::string signature = signature_path;
    PathOsNormaliseInplace(path);
    PathOsNormaliseInplace(signature);

    while(!FileExists(path + signature)) {
        if (path.empty()) {
            return std::string();
        } else {
            path = PathParent(path);
        }
    }

    return path + signature;
}

std::string PathExpand(const std::string& sPath)
{
    if(sPath.length() >0 && sPath[0] == '~') {
#ifdef _WIN_
        std::string sHomeDir;
        WCHAR path[MAX_PATH];
        if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, path))) {
            std::wstring ws(path);
            sHomeDir = std::string(ws.begin(), ws.end());
        }
#else
        std::string sHomeDir = std::string(getenv("HOME"));
#endif
        return sHomeDir + sPath.substr(1,std::string::npos);
    }else{
        return sPath;
    }
}

// Based on http://www.codeproject.com/Articles/188256/A-Simple-Wildcard-Matching-Function
bool MatchesWildcard(const std::string& str, const std::string& wildcard)
{
    const char* psQuery = str.c_str();
    const char* psWildcard = wildcard.c_str();

    while(*psWildcard)
    {
        if(*psWildcard=='?')
        {
            if(!*psQuery)
                return false;

            ++psQuery;
            ++psWildcard;
        }
        else if(*psWildcard=='*')
        {
            if(MatchesWildcard(psQuery,psWildcard+1))
                return true;

            if(*psQuery && MatchesWildcard(psQuery+1,psWildcard))
                return true;

            return false;
        }
        else
        {
            if(*psQuery++ != *psWildcard++ )
                return false;
        }
    }

    return !*psQuery && !*psWildcard;
}

std::string MakeUniqueFilename(const std::string& filename)
{
    if( FileExists(filename) ) {
        const size_t dot = filename.find_last_of('.');

        std::string fn;
        std::string ext;

        if(dot == filename.npos) {
            fn = filename;
            ext = "";
        }else{
            fn = filename.substr(0, dot);
            ext = filename.substr(dot);
        }

        int id = 1;
        std::string new_file;
        do {
            id++;
            std::stringstream ss;
            ss << fn << "_" << id << ext;
            new_file = ss.str();
        }while( FileExists(new_file) );

        return new_file;
    }else{
        return filename;
    }
}

bool IsPipe(const std::string& file)
{
#ifdef _WIN_
    return false;
#else
    struct stat st;
    int err = stat(file.c_str(), &st);
    return (err == 0) && ((st.st_mode & S_IFMT) == S_IFIFO);
#endif // _WIN_
}

bool IsPipe(int fd)
{
#ifdef _WIN_
    return false;
#else
    struct stat st;
    int err = fstat(fd, &st);
    return (err == 0) && ((st.st_mode & S_IFMT) == S_IFIFO);
#endif
}

int WritablePipeFileDescriptor(const std::string& file)
{
#ifdef _WIN_
    return false;
#else
    // open(2) will return ENXIO when there is no reader on the other
    // side of the pipe, but only if O_WRONLY|O_NONBLOCK is specified.
    // The file descriptor can be adjusted to be a blocking file
    // descriptor if it is valid.
    return open(file.c_str(), O_WRONLY | O_NONBLOCK);
#endif // _WIN_
}

int ReadablePipeFileDescriptor(const std::string& file)
{
#ifdef _WIN_
    return -1;
#else
    return open(file.c_str(), O_RDONLY | O_NONBLOCK);
#endif
}

bool PipeHasDataToRead(int fd)
{
#ifdef _WIN_
    return false;
#else
    struct pollfd pfd;
    memset(&pfd, 0, sizeof(pfd));
    pfd.fd = fd;
    pfd.events = POLLIN;

    int err = poll(&pfd, 1, 0);

    // If err is 0, the file has no data. If err is negative, an error
    // occurred.
    return err == 1 && pfd.revents & POLLIN;
#endif
}

void FlushPipe(const std::string& file)
{
#ifndef _WIN_
    int fd = open(file.c_str(), O_RDONLY | O_NONBLOCK);
    char buf[65535];
    int n = 0;
    do
    {
        n = read(fd, buf, sizeof(buf));
    } while(n > 0);
    close(fd);
#endif
}

#ifdef _WIN_

#ifdef UNICODE
    typedef std::codecvt_utf8<wchar_t> WinStringConvert;
    typedef std::wstring WinString;

    WinString s2ws(const std::string& str) {
        std::wstring_convert<WinStringConvert, wchar_t> converter;
        return converter.from_bytes(str);
    }
    std::string ws2s(const WinString& wstr) {
        std::wstring_convert<WinStringConvert, wchar_t> converter;
        return converter.to_bytes(wstr);
    }
#else
    typedef std::string WinString;
    // No conversions necessary
#   define s2ws(X) (X)
#   define ws2s(X) (X)
#endif // UNICODE

bool FilesMatchingWildcard(const std::string& wildcard, std::vector<std::string>& file_vec)
{
	size_t nLastSlash = wildcard.find_last_of("/\\");

    std::string sPath;
    std::string sFileWc;

    if(nLastSlash != std::string::npos) {
        sPath =   wildcard.substr(0, nLastSlash);
        sFileWc = wildcard.substr(nLastSlash+1, std::string::npos);
    }else{
        sPath = ".";
        sFileWc = wildcard;
    }

    sPath = PathExpand(sPath);

    WIN32_FIND_DATA wfd;
    HANDLE fh = FindFirstFile( s2ws(sPath + "\\" + sFileWc).c_str(), &wfd);

    std::vector<std::string> files;

    if (fh != INVALID_HANDLE_VALUE) {
        do {
            if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))  {
                files.push_back( sPath + "\\" + ws2s(wfd.cFileName) );
            }
        } while (FindNextFile (fh, &wfd));
        FindClose(fh);
    }

    // TOOD: Use different comparison to achieve better ordering.
    std::sort(files.begin(), files.end() );

    // Put file list at end of file_vec
    file_vec.insert(file_vec.end(), files.begin(), files.end() );

    return files.size() > 0;
}

bool FileExists(const std::string& filename)
{
    std::string search_filename = filename;
    if(filename.length() > 0 && filename[filename.length()-1] == '\\') {
        search_filename.resize(filename.length()-1);
    }
    WIN32_FIND_DATA wfd;
    HANDLE fh = FindFirstFile( s2ws(search_filename).c_str(), &wfd);
    const bool exists = fh != INVALID_HANDLE_VALUE;
    FindClose(fh);
    return exists;
}

#else // _WIN_

bool FilesMatchingWildcard(const std::string& wildcard, std::vector<std::string>& file_vec)
{
	size_t nLastSlash = wildcard.find_last_of("/\\");

    std::string sPath;
    std::string sFileWc;

    if(nLastSlash != std::string::npos) {
        sPath =   wildcard.substr(0, nLastSlash);
        sFileWc = wildcard.substr(nLastSlash+1, std::string::npos);
    }else{
        sPath = ".";
        sFileWc = wildcard;
    }

    sPath = PathExpand(sPath);

    struct dirent **namelist;
    int n = scandir(sPath.c_str(), &namelist, 0, alphasort ); // sort alpha-numeric
//    int n = scandir(sPath.c_str(), &namelist, 0, versionsort ); // sort aa1 < aa10 < aa100 etc.
    if (n >= 0){
        std::list<std::string> file_list;
        while( n-- ){
            const std::string sName(namelist[n]->d_name);
            if( sName != "." && sName != ".." && MatchesWildcard(sName, sFileWc) ) {
                const std::string sFullName = sPath + "/" + sName;
                file_list.push_front( sFullName );
            }
            free(namelist[n]);
        }
        free(namelist);

        file_vec.reserve(file_list.size());
        file_vec.insert(file_vec.begin(), file_list.begin(), file_list.end());
        return file_vec.size() > 0;
    }
    return false;
}

bool FileExists(const std::string& filename)
{
    struct stat buf;
    return stat(filename.c_str(), &buf) != -1;
}

#endif //_WIN_

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

#include <pangolin/platform.h>

#include <pangolin/utils/file_utils.h>

#ifdef _WIN_
#  define WIN32_LEAN_AND_MEAN
#  include <Windows.h>
#  include <Shlobj.h>
#else
#  include <dirent.h>
#  include <sys/types.h>
#  include <sys/stat.h>
#  include <sys/signal.h>
#  include <stdio.h>
#  include <string.h>
#  include <unistd.h>
#  include <fcntl.h>
#  include <errno.h>
#  include <poll.h>
#endif // _WIN_

#include <algorithm>
#include <sstream>
#include <list>

namespace pangolin
{

std::vector<std::string>& Split(const std::string& s, char delim, std::vector<std::string>& elements) {
    std::stringstream ss(s);
    std::string item;
    while (std::getline(ss, item, delim)) {
        elements.push_back(item);
    }
    return elements;
}

std::vector<std::string> Split(const std::string &s, char delim) {
    std::vector<std::string> elems;
    return Split(s, delim, elems);
}

std::vector<std::string> Expand(const std::string &s, char open, char close, char delim)
{
    const size_t no = s.find_first_of(open);
    if(no != std::string::npos) {
        const size_t nc = s.find_first_of(close, no);
        if(no != std::string::npos) {
            const std::string pre  = s.substr(0, no);
            const std::string mid  = s.substr(no+1, nc-no-1);
            const std::string post = s.substr(nc+1, std::string::npos);
            const std::vector<std::string> options = Split(mid, delim);
            std::vector<std::string> expansion;

            for(std::vector<std::string>::const_iterator iop = options.begin(); iop != options.end(); ++iop)
            {
                std::string full = pre + *iop + post;
                expansion.push_back(full);
            }
            return expansion;
        }
        // Open but no close is unusual. Leave it for caller to see if valid
    }

    std::vector<std::string> ret;
    ret.push_back(s);
    return ret;
}

// Make path seperator consistent for OS.
void PathOsNormaliseInplace(std::string& path)
{
#ifdef _WIN_
    std::replace(path.begin(), path.end(), '/', '\\');
#else
    std::replace(path.begin(), path.end(), '\\', '/');
#endif
}

std::string SanitizePath(const std::string& path)
{
    std::string path_copy(path.length(), '\0');

    int p_slash1 = -1;
    int p_slash0 = -1;
    int n_dots = 0;

    int dst = 0;
    for(int src=0; src < (int)path.length(); ++src) {
        if(path[src] == '/') {
            if(n_dots==1 && p_slash0 >=0) {
                dst = p_slash0;
                for(p_slash1=p_slash0-1; p_slash1>=0 && path_copy[p_slash1] != '/'; --p_slash1);
            }else if(n_dots==2) {
                if(p_slash1 >=0) {
                    dst = p_slash1;
                    p_slash0 = dst;
                    for(p_slash1=p_slash0-1; p_slash1>=0 && path_copy[p_slash1] != '/'; --p_slash1) {
                        if( path_copy[p_slash1] == '.' ) {
                            p_slash1=-1;
                            break;
                        }
                    }
                }else{
                    p_slash1 = -1;
                    p_slash0 = dst;
                }
            }else{
                p_slash1 = p_slash0;
                p_slash0 = dst;
            }
            n_dots = 0;
        }else if(path[src] == '.' ){
            if((dst-p_slash0) == n_dots+1) {
                ++n_dots;
            }
        }else{
            n_dots = 0;
        }
        path_copy[dst++] = path[src];
    }

    return path_copy.substr(0,dst);
}

// Return path 'levels' directories above 'path'
std::string PathParent(const std::string& path, int levels)
{
    std::string res = path;

    while (levels > 0) {
        if (res.length() == 0) {
            res = std::string();
            for (int l = 0; l < levels; ++l) {
#ifdef _WIN_
                res += std::string("..\\");
#else
                res += std::string("../");
#endif
            }
            return res;
        }else{
            const size_t nLastSlash = res.find_last_of("/\\");

            if (nLastSlash != std::string::npos) {
                res = path.substr(0, nLastSlash);
            } else{
                res = std::string();
            }

            --levels;
        }
    }

    return res;
}

std::string FindPath(const std::string& child_path, const std::string& signature_path)
{
    std::string path = PathExpand(child_path);
#ifdef _UNIX_
    char abs_path[PATH_MAX];
    if (realpath(path.c_str(), abs_path)) {
        path = abs_path;
    }
#endif
    std::string signature = signature_path;
    PathOsNormaliseInplace(path);
    PathOsNormaliseInplace(signature);

    while(!FileExists(path + signature)) {
        if (path.empty()) {
            return std::string();
        } else {
            path = PathParent(path);
        }
    }

    return path + signature;
}

std::string PathExpand(const std::string& sPath)
{
    if(sPath.length() >0 && sPath[0] == '~') {
#ifdef _WIN_
        std::string sHomeDir;
        WCHAR path[MAX_PATH];
        if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, path))) {
            std::wstring ws(path);
            sHomeDir = std::string(ws.begin(), ws.end());
        }
#else
        std::string sHomeDir = std::string(getenv("HOME"));
#endif
        return sHomeDir + sPath.substr(1,std::string::npos);
    }else{
        return sPath;
    }
}

// Based on http://www.codeproject.com/Articles/188256/A-Simple-Wildcard-Matching-Function
bool MatchesWildcard(const std::string& str, const std::string& wildcard)
{
    const char* psQuery = str.c_str();
    const char* psWildcard = wildcard.c_str();

    while(*psWildcard)
    {
        if(*psWildcard=='?')
        {
            if(!*psQuery)
                return false;

            ++psQuery;
            ++psWildcard;
        }
        else if(*psWildcard=='*')
        {
            if(MatchesWildcard(psQuery,psWildcard+1))
                return true;

            if(*psQuery && MatchesWildcard(psQuery+1,psWildcard))
                return true;

            return false;
        }
        else
        {
            if(*psQuery++ != *psWildcard++ )
                return false;
        }
    }

    return !*psQuery && !*psWildcard;
}

std::string MakeUniqueFilename(const std::string& filename)
{
    if( FileExists(filename) ) {
        const size_t dot = filename.find_last_of('.');

        std::string fn;
        std::string ext;

        if(dot == filename.npos) {
            fn = filename;
            ext = "";
        }else{
            fn = filename.substr(0, dot);
            ext = filename.substr(dot);
        }

        int id = 1;
        std::string new_file;
        do {
            id++;
            std::stringstream ss;
            ss << fn << "_" << id << ext;
            new_file = ss.str();
        }while( FileExists(new_file) );

        return new_file;
    }else{
        return filename;
    }
}

bool IsPipe(const std::string& file)
{
#ifdef _WIN_
    return false;
#else
    struct stat st;
    int err = stat(file.c_str(), &st);
    return (err == 0) && ((st.st_mode & S_IFMT) == S_IFIFO);
#endif // _WIN_
}

bool IsPipe(int fd)
{
#ifdef _WIN_
    return false;
#else
    struct stat st;
    int err = fstat(fd, &st);
    return (err == 0) && ((st.st_mode & S_IFMT) == S_IFIFO);
#endif
}

int WritablePipeFileDescriptor(const std::string& file)
{
#ifdef _WIN_
    return false;
#else
    // open(2) will return ENXIO when there is no reader on the other
    // side of the pipe, but only if O_WRONLY|O_NONBLOCK is specified.
    // The file descriptor can be adjusted to be a blocking file
    // descriptor if it is valid.
    return open(file.c_str(), O_WRONLY | O_NONBLOCK);
#endif // _WIN_
}

int ReadablePipeFileDescriptor(const std::string& file)
{
#ifdef _WIN_
    return -1;
#else
    return open(file.c_str(), O_RDONLY | O_NONBLOCK);
#endif
}

bool PipeHasDataToRead(int fd)
{
#ifdef _WIN_
    return false;
#else
    struct pollfd pfd;
    memset(&pfd, 0, sizeof(pfd));
    pfd.fd = fd;
    pfd.events = POLLIN;

    int err = poll(&pfd, 1, 0);

    // If err is 0, the file has no data. If err is negative, an error
    // occurred.
    return err == 1 && pfd.revents & POLLIN;
#endif
}

void FlushPipe(const std::string& file)
{
#ifndef _WIN_
    int fd = open(file.c_str(), O_RDONLY | O_NONBLOCK);
    char buf[65535];
    int n = 0;
    do
    {
        n = read(fd, buf, sizeof(buf));
    } while(n > 0);
    close(fd);
#endif
}

#ifdef _WIN_

#ifdef UNICODE
    typedef std::codecvt_utf8<wchar_t> WinStringConvert;
    typedef std::wstring WinString;

    WinString s2ws(const std::string& str) {
        std::wstring_convert<WinStringConvert, wchar_t> converter;
        return converter.from_bytes(str);
    }
    std::string ws2s(const WinString& wstr) {
        std::wstring_convert<WinStringConvert, wchar_t> converter;
        return converter.to_bytes(wstr);
    }
#else
    typedef std::string WinString;
    // No conversions necessary
#   define s2ws(X) (X)
#   define ws2s(X) (X)
#endif // UNICODE

bool FilesMatchingWildcard(const std::string& wildcard, std::vector<std::string>& file_vec)
{
	size_t nLastSlash = wildcard.find_last_of("/\\");

    std::string sPath;
    std::string sFileWc;

    if(nLastSlash != std::string::npos) {
        sPath =   wildcard.substr(0, nLastSlash);
        sFileWc = wildcard.substr(nLastSlash+1, std::string::npos);
    }else{
        sPath = ".";
        sFileWc = wildcard;
    }

    sPath = PathExpand(sPath);

    WIN32_FIND_DATA wfd;
    HANDLE fh = FindFirstFile( s2ws(sPath + "\\" + sFileWc).c_str(), &wfd);

    std::vector<std::string> files;

    if (fh != INVALID_HANDLE_VALUE) {
        do {
            if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))  {
                files.push_back( sPath + "\\" + ws2s(wfd.cFileName) );
            }
        } while (FindNextFile (fh, &wfd));
        FindClose(fh);
    }

    // TOOD: Use different comparison to achieve better ordering.
    std::sort(files.begin(), files.end() );

    // Put file list at end of file_vec
    file_vec.insert(file_vec.end(), files.begin(), files.end() );

    return files.size() > 0;
}

bool FileExists(const std::string& filename)
{
    std::string search_filename = filename;
    if(filename.length() > 0 && filename[filename.length()-1] == '\\') {
        search_filename.resize(filename.length()-1);
    }
    WIN32_FIND_DATA wfd;
    HANDLE fh = FindFirstFile( s2ws(search_filename).c_str(), &wfd);
    const bool exists = fh != INVALID_HANDLE_VALUE;
    FindClose(fh);
    return exists;
}

#else // _WIN_

bool FilesMatchingWildcard(const std::string& wildcard, std::vector<std::string>& file_vec)
{
	size_t nLastSlash = wildcard.find_last_of("/\\");

    std::string sPath;
    std::string sFileWc;

    if(nLastSlash != std::string::npos) {
        sPath =   wildcard.substr(0, nLastSlash);
        sFileWc = wildcard.substr(nLastSlash+1, std::string::npos);
    }else{
        sPath = ".";
        sFileWc = wildcard;
    }

    sPath = PathExpand(sPath);

    struct dirent **namelist;
    int n = scandir(sPath.c_str(), &namelist, 0, alphasort ); // sort alpha-numeric
//    int n = scandir(sPath.c_str(), &namelist, 0, versionsort ); // sort aa1 < aa10 < aa100 etc.
    if (n >= 0){
        std::list<std::string> file_list;
        while( n-- ){
            const std::string sName(namelist[n]->d_name);
            if( sName != "." && sName != ".." && MatchesWildcard(sName, sFileWc) ) {
                const std::string sFullName = sPath + "/" + sName;
                file_list.push_front( sFullName );
            }
            free(namelist[n]);
        }
        free(namelist);

        file_vec.reserve(file_list.size());
        file_vec.insert(file_vec.begin(), file_list.begin(), file_list.end());
        return file_vec.size() > 0;
    }
    return false;
}

bool FileExists(const std::string& filename)
{
    struct stat buf;
    return stat(filename.c_str(), &buf) != -1;
}

#endif //_WIN_

}
<|endoftext|>


<commit_before>/*
** Copyright 2013-2014 Merethis
**
** This file is part of Centreon Broker.
**
** Centreon Broker is free software: you can redistribute it and/or
** modify it under the terms of the GNU General Public License version 2
** as published by the Free Software Foundation.
**
** Centreon Broker is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Centreon Broker. If not, see
** <http://www.gnu.org/licenses/>.
*/

#ifndef CCB_BBDO_INTERNAL_HH
#  define CCB_BBDO_INTERNAL_HH

#  include <QByteArray>
#  include <vector>
#  include "com/centreon/broker/namespace.hh"
#  include "mapping.hh"

#  define BBDO_HEADER_SIZE 8
#  define BBDO_VERSION_MAJOR 1
#  define BBDO_VERSION_MINOR 1
#  define BBDO_VERSION_PATCH 1

#  define BBDO_NEB_TYPE 1u
#  define BBDO_STORAGE_TYPE 2u
#  define BBDO_CORRELATION_TYPE 3u
#  define BBDO_BAM_TYPE 4u
#  define BBDO_INTERNAL_TYPE 65535u
#  define BBDO_ID(type, id) ((type << 16) | id)

CCB_BEGIN()

namespace                 bbdo {
  // Data elements.
  enum {
    de_version_response = 1
  };

  template                <typename T>
  struct                  getter_setter {
    data_member<T> const* member;
    void (*               getter)(
                            T const&,
                            data_member<T> const&,
                            QByteArray&);
    unsigned int (*       setter)(
                            T&,
                            data_member<T> const&,
                            void const*,
                            unsigned int);
  };

  // BBDO mappings.
  template                <typename T>
  struct                  bbdo_mapped_type {
    static std::vector<getter_setter<T> > table;
  };

  // Mapping initialization routin.e
  void initialize();
}

CCB_END()

#endif // !CCB_BBDO_INTERNAL_HH
<commit_msg>BBDO: bump BBDO version to 1.2.0<commit_after>/*
** Copyright 2013-2014 Merethis
**
** This file is part of Centreon Broker.
**
** Centreon Broker is free software: you can redistribute it and/or
** modify it under the terms of the GNU General Public License version 2
** as published by the Free Software Foundation.
**
** Centreon Broker is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Centreon Broker. If not, see
** <http://www.gnu.org/licenses/>.
*/

#ifndef CCB_BBDO_INTERNAL_HH
#  define CCB_BBDO_INTERNAL_HH

#  include <QByteArray>
#  include <vector>
#  include "com/centreon/broker/namespace.hh"
#  include "mapping.hh"

#  define BBDO_HEADER_SIZE 8
#  define BBDO_VERSION_MAJOR 1
#  define BBDO_VERSION_MINOR 2
#  define BBDO_VERSION_PATCH 0

#  define BBDO_NEB_TYPE 1u
#  define BBDO_STORAGE_TYPE 2u
#  define BBDO_CORRELATION_TYPE 3u
#  define BBDO_BAM_TYPE 4u
#  define BBDO_INTERNAL_TYPE 65535u
#  define BBDO_ID(type, id) ((type << 16) | id)

CCB_BEGIN()

namespace                 bbdo {
  // Data elements.
  enum {
    de_version_response = 1
  };

  template                <typename T>
  struct                  getter_setter {
    data_member<T> const* member;
    void (*               getter)(
                            T const&,
                            data_member<T> const&,
                            QByteArray&);
    unsigned int (*       setter)(
                            T&,
                            data_member<T> const&,
                            void const*,
                            unsigned int);
  };

  // BBDO mappings.
  template                <typename T>
  struct                  bbdo_mapped_type {
    static std::vector<getter_setter<T> > table;
  };

  // Mapping initialization routin.e
  void initialize();
}

CCB_END()

#endif // !CCB_BBDO_INTERNAL_HH
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2010 Google Inc.  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 Google Inc. 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 "config.h"

#include "core/fileapi/FileReaderLoader.h"

#include "core/dom/ScriptExecutionContext.h"
#include "core/fetch/TextResourceDecoder.h"
#include "core/fileapi/Blob.h"
#include "core/fileapi/BlobRegistry.h"
#include "core/fileapi/BlobURL.h"
#include "core/fileapi/FileReaderLoaderClient.h"
#include "core/fileapi/Stream.h"
#include "core/loader/ThreadableLoader.h"
#include "core/platform/network/ResourceRequest.h"
#include "core/platform/network/ResourceResponse.h"
#include "wtf/ArrayBuffer.h"
#include "wtf/PassRefPtr.h"
#include "wtf/RefPtr.h"
#include "wtf/Vector.h"
#include "wtf/text/Base64.h"
#include "wtf/text/StringBuilder.h"

using namespace std;

namespace WebCore {

const int defaultBufferLength = 32768;

FileReaderLoader::FileReaderLoader(ReadType readType, FileReaderLoaderClient* client)
    : m_readType(readType)
    , m_client(client)
    , m_isRawDataConverted(false)
    , m_stringResult("")
    , m_variableLength(false)
    , m_bytesLoaded(0)
    , m_totalBytes(0)
    , m_hasRange(false)
    , m_rangeStart(0)
    , m_rangeEnd(0)
    , m_errorCode(FileError::OK)
{
}

FileReaderLoader::~FileReaderLoader()
{
    terminate();
    if (!m_urlForReading.isEmpty())
        BlobRegistry::unregisterBlobURL(m_urlForReading);
}

void FileReaderLoader::startForURL(ScriptExecutionContext* scriptExecutionContext, const KURL& url)
{
    // The blob is read by routing through the request handling layer given a temporary public url.
    m_urlForReading = BlobURL::createPublicURL(scriptExecutionContext->securityOrigin());
    if (m_urlForReading.isEmpty()) {
        failed(FileError::SECURITY_ERR);
        return;
    }
    BlobRegistry::registerBlobURL(scriptExecutionContext->securityOrigin(), m_urlForReading, url);

    // Construct and load the request.
    ResourceRequest request(m_urlForReading);
    request.setHTTPMethod("GET");
    if (m_hasRange)
        request.setHTTPHeaderField("Range", String::format("bytes=%d-%d", m_rangeStart, m_rangeEnd));

    ThreadableLoaderOptions options;
    options.sendLoadCallbacks = SendCallbacks;
    options.sniffContent = DoNotSniffContent;
    options.preflightPolicy = ConsiderPreflight;
    options.allowCredentials = AllowStoredCredentials;
    options.crossOriginRequestPolicy = DenyCrossOriginRequests;
    // FIXME: Is there a directive to which this load should be subject?
    options.contentSecurityPolicyEnforcement = DoNotEnforceContentSecurityPolicy;

    if (m_client)
        m_loader = ThreadableLoader::create(scriptExecutionContext, this, request, options);
    else
        ThreadableLoader::loadResourceSynchronously(scriptExecutionContext, request, *this, options);
}

void FileReaderLoader::start(ScriptExecutionContext* scriptExecutionContext, const Blob& blob)
{
    startForURL(scriptExecutionContext, blob.url());
}

void FileReaderLoader::start(ScriptExecutionContext* scriptExecutionContext, const Stream& stream)
{
    startForURL(scriptExecutionContext, stream.url());
}

void FileReaderLoader::cancel()
{
    m_errorCode = FileError::ABORT_ERR;
    terminate();
}

void FileReaderLoader::terminate()
{
    if (m_loader) {
        m_loader->cancel();
        cleanup();
    }
}

void FileReaderLoader::cleanup()
{
    m_loader = 0;

    // If we get any error, we do not need to keep a buffer around.
    if (m_errorCode) {
        m_rawData = 0;
        m_stringResult = "";
    }
}

void FileReaderLoader::didReceiveResponse(unsigned long, const ResourceResponse& response)
{
    if (response.httpStatusCode() != 200) {
        failed(httpStatusCodeToErrorCode(response.httpStatusCode()));
        return;
    }

    unsigned long long length = response.expectedContentLength();

    // A value larger than INT_MAX means that the content length wasn't
    // specified, so the buffer will need to be dynamically grown.
    if (length > INT_MAX) {
        m_variableLength = true;
        if (m_hasRange)
            length = 1 + m_rangeEnd - m_rangeStart;
        else
            length = defaultBufferLength;
    }

    // Check that we can cast to unsigned since we have to do
    // so to call ArrayBuffer's create function.
    // FIXME: Support reading more than the current size limit of ArrayBuffer.
    if (length > numeric_limits<unsigned>::max()) {
        failed(FileError::NOT_READABLE_ERR);
        return;
    }

    ASSERT(!m_rawData);
    m_rawData = ArrayBuffer::create(static_cast<unsigned>(length), 1);

    if (!m_rawData) {
        failed(FileError::NOT_READABLE_ERR);
        return;
    }

    m_totalBytes = static_cast<unsigned>(length);

    if (m_client)
        m_client->didStartLoading();
}

void FileReaderLoader::didReceiveData(const char* data, int dataLength)
{
    ASSERT(data);
    ASSERT(dataLength > 0);

    // Bail out if we already encountered an error.
    if (m_errorCode)
        return;

    int length = dataLength;
    unsigned remainingBufferSpace = m_totalBytes - m_bytesLoaded;
    if (length > static_cast<long long>(remainingBufferSpace)) {
        // If the buffer has hit maximum size, it can't be grown any more.
        if (m_totalBytes >= numeric_limits<unsigned>::max()) {
            failed(FileError::NOT_READABLE_ERR);
            return;
        }
        if (m_variableLength) {
            unsigned long long newLength = m_totalBytes * 2;
            if (newLength > numeric_limits<unsigned>::max())
                newLength = numeric_limits<unsigned>::max();
            RefPtr<ArrayBuffer> newData =
                ArrayBuffer::create(static_cast<unsigned>(newLength), 1);
            memcpy(static_cast<char*>(newData->data()), static_cast<char*>(m_rawData->data()), m_bytesLoaded);

            m_rawData = newData;
            m_totalBytes = static_cast<unsigned>(newLength);
        } else
            length = remainingBufferSpace;
    }

    if (length <= 0)
        return;

    memcpy(static_cast<char*>(m_rawData->data()) + m_bytesLoaded, data, length);
    m_bytesLoaded += length;

    m_isRawDataConverted = false;

    if (m_client)
        m_client->didReceiveData();
}

void FileReaderLoader::didFinishLoading(unsigned long, double)
{
    if (m_variableLength && m_totalBytes > m_bytesLoaded) {
        RefPtr<ArrayBuffer> newData = m_rawData->slice(0, m_bytesLoaded);

        m_rawData = newData;
        m_totalBytes = m_bytesLoaded;
    }
    cleanup();
    if (m_client)
        m_client->didFinishLoading();
}

void FileReaderLoader::didFail(const ResourceError&)
{
    // If we're aborting, do not proceed with normal error handling since it is covered in aborting code.
    if (m_errorCode == FileError::ABORT_ERR)
        return;

    failed(FileError::NOT_READABLE_ERR);
}

void FileReaderLoader::failed(FileError::ErrorCode errorCode)
{
    m_errorCode = errorCode;
    cleanup();
    if (m_client)
        m_client->didFail(m_errorCode);
}

FileError::ErrorCode FileReaderLoader::httpStatusCodeToErrorCode(int httpStatusCode)
{
    switch (httpStatusCode) {
    case 403:
        return FileError::SECURITY_ERR;
    case 404:
        return FileError::NOT_FOUND_ERR;
    default:
        return FileError::NOT_READABLE_ERR;
    }
}

PassRefPtr<ArrayBuffer> FileReaderLoader::arrayBufferResult() const
{
    ASSERT(m_readType == ReadAsArrayBuffer);

    // If the loading is not started or an error occurs, return an empty result.
    if (!m_rawData || m_errorCode)
        return 0;

    // If completed, we can simply return our buffer.
    if (isCompleted())
        return m_rawData;

    // Otherwise, return a copy.
    return m_rawData->slice(0, m_bytesLoaded);
}

String FileReaderLoader::stringResult()
{
    ASSERT(m_readType != ReadAsArrayBuffer && m_readType != ReadAsBlob);

    // If the loading is not started or an error occurs, return an empty result.
    if (!m_rawData || m_errorCode)
        return m_stringResult;

    // If already converted from the raw data, return the result now.
    if (m_isRawDataConverted)
        return m_stringResult;

    switch (m_readType) {
    case ReadAsArrayBuffer:
        // No conversion is needed.
        break;
    case ReadAsBinaryString:
        m_stringResult = String(static_cast<const char*>(m_rawData->data()), m_bytesLoaded);
        break;
    case ReadAsText:
        convertToText();
        break;
    case ReadAsDataURL:
        // Partial data is not supported when reading as data URL.
        if (isCompleted())
            convertToDataURL();
        break;
    default:
        ASSERT_NOT_REACHED();
    }

    return m_stringResult;
}

void FileReaderLoader::convertToText()
{
    if (!m_bytesLoaded)
        return;

    // Decode the data.
    // The File API spec says that we should use the supplied encoding if it is valid. However, we choose to ignore this
    // requirement in order to be consistent with how WebKit decodes the web content: always has the BOM override the
    // provided encoding.
    // FIXME: consider supporting incremental decoding to improve the perf.
    StringBuilder builder;
    if (!m_decoder)
        m_decoder = TextResourceDecoder::create("text/plain", m_encoding.isValid() ? m_encoding : UTF8Encoding());
    builder.append(m_decoder->decode(static_cast<const char*>(m_rawData->data()), m_bytesLoaded));

    if (isCompleted())
        builder.append(m_decoder->flush());

    m_stringResult = builder.toString();
}

void FileReaderLoader::convertToDataURL()
{
    StringBuilder builder;
    builder.append("data:");

    if (!m_bytesLoaded) {
        m_stringResult = builder.toString();
        return;
    }

    builder.append(m_dataType);
    builder.append(";base64,");

    Vector<char> out;
    base64Encode(static_cast<const char*>(m_rawData->data()), m_bytesLoaded, out);
    out.append('\0');
    builder.append(out.data());

    m_stringResult = builder.toString();
}

bool FileReaderLoader::isCompleted() const
{
    return m_bytesLoaded == m_totalBytes;
}

void FileReaderLoader::setEncoding(const String& encoding)
{
    if (!encoding.isEmpty())
        m_encoding = WTF::TextEncoding(encoding);
}

} // namespace WebCore
<commit_msg>Fix converted result caching in FileReaderLoader::stringResult()<commit_after>/*
 * Copyright (C) 2010 Google Inc.  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 Google Inc. 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 "config.h"

#include "core/fileapi/FileReaderLoader.h"

#include "core/dom/ScriptExecutionContext.h"
#include "core/fetch/TextResourceDecoder.h"
#include "core/fileapi/Blob.h"
#include "core/fileapi/BlobRegistry.h"
#include "core/fileapi/BlobURL.h"
#include "core/fileapi/FileReaderLoaderClient.h"
#include "core/fileapi/Stream.h"
#include "core/loader/ThreadableLoader.h"
#include "core/platform/network/ResourceRequest.h"
#include "core/platform/network/ResourceResponse.h"
#include "wtf/ArrayBuffer.h"
#include "wtf/PassRefPtr.h"
#include "wtf/RefPtr.h"
#include "wtf/Vector.h"
#include "wtf/text/Base64.h"
#include "wtf/text/StringBuilder.h"

using namespace std;

namespace WebCore {

const int defaultBufferLength = 32768;

FileReaderLoader::FileReaderLoader(ReadType readType, FileReaderLoaderClient* client)
    : m_readType(readType)
    , m_client(client)
    , m_isRawDataConverted(false)
    , m_stringResult("")
    , m_variableLength(false)
    , m_bytesLoaded(0)
    , m_totalBytes(0)
    , m_hasRange(false)
    , m_rangeStart(0)
    , m_rangeEnd(0)
    , m_errorCode(FileError::OK)
{
}

FileReaderLoader::~FileReaderLoader()
{
    terminate();
    if (!m_urlForReading.isEmpty())
        BlobRegistry::unregisterBlobURL(m_urlForReading);
}

void FileReaderLoader::startForURL(ScriptExecutionContext* scriptExecutionContext, const KURL& url)
{
    // The blob is read by routing through the request handling layer given a temporary public url.
    m_urlForReading = BlobURL::createPublicURL(scriptExecutionContext->securityOrigin());
    if (m_urlForReading.isEmpty()) {
        failed(FileError::SECURITY_ERR);
        return;
    }
    BlobRegistry::registerBlobURL(scriptExecutionContext->securityOrigin(), m_urlForReading, url);

    // Construct and load the request.
    ResourceRequest request(m_urlForReading);
    request.setHTTPMethod("GET");
    if (m_hasRange)
        request.setHTTPHeaderField("Range", String::format("bytes=%d-%d", m_rangeStart, m_rangeEnd));

    ThreadableLoaderOptions options;
    options.sendLoadCallbacks = SendCallbacks;
    options.sniffContent = DoNotSniffContent;
    options.preflightPolicy = ConsiderPreflight;
    options.allowCredentials = AllowStoredCredentials;
    options.crossOriginRequestPolicy = DenyCrossOriginRequests;
    // FIXME: Is there a directive to which this load should be subject?
    options.contentSecurityPolicyEnforcement = DoNotEnforceContentSecurityPolicy;

    if (m_client)
        m_loader = ThreadableLoader::create(scriptExecutionContext, this, request, options);
    else
        ThreadableLoader::loadResourceSynchronously(scriptExecutionContext, request, *this, options);
}

void FileReaderLoader::start(ScriptExecutionContext* scriptExecutionContext, const Blob& blob)
{
    startForURL(scriptExecutionContext, blob.url());
}

void FileReaderLoader::start(ScriptExecutionContext* scriptExecutionContext, const Stream& stream)
{
    startForURL(scriptExecutionContext, stream.url());
}

void FileReaderLoader::cancel()
{
    m_errorCode = FileError::ABORT_ERR;
    terminate();
}

void FileReaderLoader::terminate()
{
    if (m_loader) {
        m_loader->cancel();
        cleanup();
    }
}

void FileReaderLoader::cleanup()
{
    m_loader = 0;

    // If we get any error, we do not need to keep a buffer around.
    if (m_errorCode) {
        m_rawData = 0;
        m_stringResult = "";
        m_isRawDataConverted = true;
    }
}

void FileReaderLoader::didReceiveResponse(unsigned long, const ResourceResponse& response)
{
    if (response.httpStatusCode() != 200) {
        failed(httpStatusCodeToErrorCode(response.httpStatusCode()));
        return;
    }

    unsigned long long length = response.expectedContentLength();

    // A value larger than INT_MAX means that the content length wasn't
    // specified, so the buffer will need to be dynamically grown.
    if (length > INT_MAX) {
        m_variableLength = true;
        if (m_hasRange)
            length = 1 + m_rangeEnd - m_rangeStart;
        else
            length = defaultBufferLength;
    }

    // Check that we can cast to unsigned since we have to do
    // so to call ArrayBuffer's create function.
    // FIXME: Support reading more than the current size limit of ArrayBuffer.
    if (length > numeric_limits<unsigned>::max()) {
        failed(FileError::NOT_READABLE_ERR);
        return;
    }

    ASSERT(!m_rawData);
    m_rawData = ArrayBuffer::create(static_cast<unsigned>(length), 1);

    if (!m_rawData) {
        failed(FileError::NOT_READABLE_ERR);
        return;
    }

    m_totalBytes = static_cast<unsigned>(length);

    if (m_client)
        m_client->didStartLoading();
}

void FileReaderLoader::didReceiveData(const char* data, int dataLength)
{
    ASSERT(data);
    ASSERT(dataLength > 0);

    // Bail out if we already encountered an error.
    if (m_errorCode)
        return;

    int length = dataLength;
    unsigned remainingBufferSpace = m_totalBytes - m_bytesLoaded;
    if (length > static_cast<long long>(remainingBufferSpace)) {
        // If the buffer has hit maximum size, it can't be grown any more.
        if (m_totalBytes >= numeric_limits<unsigned>::max()) {
            failed(FileError::NOT_READABLE_ERR);
            return;
        }
        if (m_variableLength) {
            unsigned long long newLength = m_totalBytes * 2;
            if (newLength > numeric_limits<unsigned>::max())
                newLength = numeric_limits<unsigned>::max();
            RefPtr<ArrayBuffer> newData =
                ArrayBuffer::create(static_cast<unsigned>(newLength), 1);
            memcpy(static_cast<char*>(newData->data()), static_cast<char*>(m_rawData->data()), m_bytesLoaded);

            m_rawData = newData;
            m_totalBytes = static_cast<unsigned>(newLength);
        } else
            length = remainingBufferSpace;
    }

    if (length <= 0)
        return;

    memcpy(static_cast<char*>(m_rawData->data()) + m_bytesLoaded, data, length);
    m_bytesLoaded += length;

    m_isRawDataConverted = false;

    if (m_client)
        m_client->didReceiveData();
}

void FileReaderLoader::didFinishLoading(unsigned long, double)
{
    if (m_variableLength && m_totalBytes > m_bytesLoaded) {
        RefPtr<ArrayBuffer> newData = m_rawData->slice(0, m_bytesLoaded);

        m_rawData = newData;
        m_isRawDataConverted = false;

        m_totalBytes = m_bytesLoaded;
    }
    cleanup();
    if (m_client)
        m_client->didFinishLoading();
}

void FileReaderLoader::didFail(const ResourceError&)
{
    // If we're aborting, do not proceed with normal error handling since it is covered in aborting code.
    if (m_errorCode == FileError::ABORT_ERR)
        return;

    failed(FileError::NOT_READABLE_ERR);
}

void FileReaderLoader::failed(FileError::ErrorCode errorCode)
{
    m_errorCode = errorCode;
    cleanup();
    if (m_client)
        m_client->didFail(m_errorCode);
}

FileError::ErrorCode FileReaderLoader::httpStatusCodeToErrorCode(int httpStatusCode)
{
    switch (httpStatusCode) {
    case 403:
        return FileError::SECURITY_ERR;
    case 404:
        return FileError::NOT_FOUND_ERR;
    default:
        return FileError::NOT_READABLE_ERR;
    }
}

PassRefPtr<ArrayBuffer> FileReaderLoader::arrayBufferResult() const
{
    ASSERT(m_readType == ReadAsArrayBuffer);

    // If the loading is not started or an error occurs, return an empty result.
    if (!m_rawData || m_errorCode)
        return 0;

    // If completed, we can simply return our buffer.
    if (isCompleted())
        return m_rawData;

    // Otherwise, return a copy.
    return m_rawData->slice(0, m_bytesLoaded);
}

String FileReaderLoader::stringResult()
{
    ASSERT(m_readType != ReadAsArrayBuffer && m_readType != ReadAsBlob);

    // If the loading is not started or an error occurs, return an empty result.
    if (!m_rawData || m_errorCode)
        return m_stringResult;

    // If already converted from the raw data, return the result now.
    if (m_isRawDataConverted)
        return m_stringResult;

    switch (m_readType) {
    case ReadAsArrayBuffer:
        // No conversion is needed.
        break;
    case ReadAsBinaryString:
        m_stringResult = String(static_cast<const char*>(m_rawData->data()), m_bytesLoaded);
        m_isRawDataConverted = true;
        break;
    case ReadAsText:
        convertToText();
        break;
    case ReadAsDataURL:
        // Partial data is not supported when reading as data URL.
        if (isCompleted())
            convertToDataURL();
        break;
    default:
        ASSERT_NOT_REACHED();
    }

    return m_stringResult;
}

void FileReaderLoader::convertToText()
{
    m_isRawDataConverted = true;

    if (!m_bytesLoaded) {
        m_stringResult = "";
        return;
    }

    // Decode the data.
    // The File API spec says that we should use the supplied encoding if it is valid. However, we choose to ignore this
    // requirement in order to be consistent with how WebKit decodes the web content: always has the BOM override the
    // provided encoding.
    // FIXME: consider supporting incremental decoding to improve the perf.
    StringBuilder builder;
    if (!m_decoder)
        m_decoder = TextResourceDecoder::create("text/plain", m_encoding.isValid() ? m_encoding : UTF8Encoding());
    builder.append(m_decoder->decode(static_cast<const char*>(m_rawData->data()), m_bytesLoaded));

    if (isCompleted())
        builder.append(m_decoder->flush());

    m_stringResult = builder.toString();
}

void FileReaderLoader::convertToDataURL()
{
    m_isRawDataConverted = true;

    StringBuilder builder;
    builder.append("data:");

    if (!m_bytesLoaded) {
        m_stringResult = builder.toString();
        return;
    }

    builder.append(m_dataType);
    builder.append(";base64,");

    Vector<char> out;
    base64Encode(static_cast<const char*>(m_rawData->data()), m_bytesLoaded, out);
    out.append('\0');
    builder.append(out.data());

    m_stringResult = builder.toString();
}

bool FileReaderLoader::isCompleted() const
{
    return m_bytesLoaded == m_totalBytes;
}

void FileReaderLoader::setEncoding(const String& encoding)
{
    if (!encoding.isEmpty())
        m_encoding = WTF::TextEncoding(encoding);
}

} // namespace WebCore
<|endoftext|>


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

#include "base/stringpiece.h"

#include <cstdarg>
#include <cstdio>

#include <string>

namespace operations_research {

void StringAppendV(std::string* const dst,
                   const char* const format,
                   va_list ap) {
  // First try with a small fixed size buffer
  char space[1024];

  // It's possible for methods that use a va_list to invalidate
  // the data in it upon use.  The fix is to make a copy
  // of the structure before using it and use that copy instead.
  va_list backup_ap;
#if defined(_MSC_VER)
  backup_ap = ap;
#else
  va_copy(backup_ap, ap);
#endif
  int result = vsnprintf(space, sizeof(space), format, backup_ap);
  va_end(backup_ap);

  if ((result >= 0) && (result < sizeof(space))) {
    // It fit
    dst->append(space, result);
    return;
  }

  // Repeatedly increase buffer size until it fits
  int length = sizeof(space);
  while (true) {
    if (result < 0) {
      // Older behavior: just try doubling the buffer size
      length *= 2;
    } else {
      // We need exactly "result+1" characters
      length = result+1;
    }
    char* const buf = new char[length];

    // Restore the va_list before we use it again
#if defined(_MSC_VER)
  backup_ap = ap;
#else
    va_copy(backup_ap, ap);
#endif
    result = vsnprintf(buf, length, format, backup_ap);
    va_end(backup_ap);

    if ((result >= 0) && (result < length)) {
      // It fit
      dst->append(buf, result);
      delete[] buf;
      return;
    }
    delete[] buf;
  }
}

std::string StringPrintf(const char* const format, ...) {
  va_list ap;
  va_start(ap, format);
  std::string result;
  StringAppendV(&result, format, ap);
  va_end(ap);
  return result;
}

void SStringPrintf(std::string* const dst, const char* const format, ...) {
  va_list ap;
  va_start(ap, format);
  dst->clear();
  StringAppendV(dst, format, ap);
  va_end(ap);
}

void StringAppendF(std::string* const dst, const char* const format, ...) {
  va_list ap;
  va_start(ap, format);
  StringAppendV(dst, format, ap);
  va_end(ap);
}
}  // namespace operations_research
<commit_msg>small fix on base dependencies<commit_after>// Copyright 2010 Google
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "base/stringprintf.h"

#include <cstdarg>
#include <cstdio>

#include <string>

namespace operations_research {

void StringAppendV(std::string* const dst,
                   const char* const format,
                   va_list ap) {
  // First try with a small fixed size buffer
  char space[1024];

  // It's possible for methods that use a va_list to invalidate
  // the data in it upon use.  The fix is to make a copy
  // of the structure before using it and use that copy instead.
  va_list backup_ap;
#if defined(_MSC_VER)
  backup_ap = ap;
#else
  va_copy(backup_ap, ap);
#endif
  int result = vsnprintf(space, sizeof(space), format, backup_ap);
  va_end(backup_ap);

  if ((result >= 0) && (result < sizeof(space))) {
    // It fit
    dst->append(space, result);
    return;
  }

  // Repeatedly increase buffer size until it fits
  int length = sizeof(space);
  while (true) {
    if (result < 0) {
      // Older behavior: just try doubling the buffer size
      length *= 2;
    } else {
      // We need exactly "result+1" characters
      length = result+1;
    }
    char* const buf = new char[length];

    // Restore the va_list before we use it again
#if defined(_MSC_VER)
  backup_ap = ap;
#else
    va_copy(backup_ap, ap);
#endif
    result = vsnprintf(buf, length, format, backup_ap);
    va_end(backup_ap);

    if ((result >= 0) && (result < length)) {
      // It fit
      dst->append(buf, result);
      delete[] buf;
      return;
    }
    delete[] buf;
  }
}

std::string StringPrintf(const char* const format, ...) {
  va_list ap;
  va_start(ap, format);
  std::string result;
  StringAppendV(&result, format, ap);
  va_end(ap);
  return result;
}

void SStringPrintf(std::string* const dst, const char* const format, ...) {
  va_list ap;
  va_start(ap, format);
  dst->clear();
  StringAppendV(dst, format, ap);
  va_end(ap);
}

void StringAppendF(std::string* const dst, const char* const format, ...) {
  va_list ap;
  va_start(ap, format);
  StringAppendV(dst, format, ap);
  va_end(ap);
}
}  // namespace operations_research
<|endoftext|>


<commit_before>/*
 * This file is part of `et engine`
 * Copyright 2009-2015 by Sergey Reznik
 * Please, modify content only if you know what are you doing.
 *
 */

#include <et/core/objectscache.h>

using namespace et;

ObjectsCache::ObjectsCache() :
	_updateTime(0.0f)
{
}

ObjectsCache::~ObjectsCache()
{
	clear();
}

void ObjectsCache::manage(const LoadableObject::Pointer& o, const ObjectLoader::Pointer& loader)
{
	if (o.valid() && o->canBeReloaded())
	{
		CriticalSectionScope lock(_lock);

		if (_objects.count(o->origin()) > 0)
		{
			ObjectPropertyList& list = _objects[o->origin()];
			list.push_back(ObjectProperty(o, loader));
			ObjectProperty& newObject = list.back();
			newObject.identifiers[o->origin()] = getFileProperty(o->origin());
			for (auto& s : o->distributedOrigins())
				newObject.identifiers[s] = getFileProperty(s);
		}
		else
		{
			ObjectPropertyList newList(1, ObjectProperty(o, loader));
			ObjectProperty& newObject = newList.back();
			newObject.identifiers[o->origin()] = getFileProperty(o->origin());
			for (auto& s : o->distributedOrigins())
				newObject.identifiers[s] = getFileProperty(s);
			_objects.insert(std::make_pair(o->origin(), newList));
		}
	}
	else
	{
		log::warning("[ObjectsCache] Trying to manage invalid object");
	}
}

std::vector<LoadableObject::Pointer> ObjectsCache::findObjects(const std::string& key)
{
	CriticalSectionScope lock(_lock);
	auto i = _objects.find(key);
	if (i == _objects.end())
		return std::vector<LoadableObject::Pointer>();

	std::vector<LoadableObject::Pointer> result;

	for (auto prop : i->second)
		result.push_back(prop.object);

	return result;
}

LoadableObject::Pointer ObjectsCache::findAnyObject(const std::string& key, uint64_t* property)
{
	CriticalSectionScope lock(_lock);

	auto i = _objects.find(key);
	if (i == _objects.end())
	{
		if (property)
			*property = 0;

		return  LoadableObject::Pointer();
	}
	else
	{
		if (property)
			*property = i->second.front().identifiers[key];

		return i->second.front().object;
	}
}

void ObjectsCache::discard(const LoadableObject::Pointer& o)
{
	if (o.valid())
	{
		CriticalSectionScope lock(_lock);
		if (_objects.count(o->origin()) == 0) return;

		ObjectPropertyList& list = _objects[o->origin()];
		for (auto i = list.begin(), e = list.end(); i != e; ++i)
		{
			if (i->object == o)
			{
				list.erase(i);
				break;
			}
		}

		if (list.empty())
			_objects.erase(o->origin());
	}
}

void ObjectsCache::clear()
{
	CriticalSectionScope lock(_lock);
	_objects.clear();
}

void ObjectsCache::flush()
{
	CriticalSectionScope lock(_lock);

	size_t objectsErased = 0;

	for (auto& lv : _objects)
	{
		auto obj = lv.second.begin();
		while (obj != lv.second.end())
		{
			if (obj->object->atomicCounterValue() == 1)
			{
				obj = lv.second.erase(obj);
				++objectsErased;
			}
			else
			{
				++obj;
			}
		}
	}

	auto i = _objects.begin();
	while (i != _objects.end())
	{
		if (i->second.empty())
		{
			i = _objects.erase(i);
		}
		else
		{
			++i;
		}
	}

	if (objectsErased > 0)
		log::info("[ObjectsCache] %llu objects flushed.", static_cast<uint64_t>(objectsErased));
}

void ObjectsCache::startMonitoring()
{
	startUpdates();
}

void ObjectsCache::stopMonitoring()
{
	cancelUpdates();
}

void ObjectsCache::update(float t)
{
	static const float updateInterval = 0.5f;

	if (_updateTime == 0.0f)
		_updateTime = t;

	float dt = t - _updateTime;

	if (dt > updateInterval)
	{
		performUpdate();
		_updateTime = t;
	}
}

uint64_t ObjectsCache::getFileProperty(const std::string& p)
{
	return getFileDate(p);
}

uint64_t ObjectsCache::getObjectProperty(LoadableObject::Pointer ptr)
{
	CriticalSectionScope lock(_lock);

	for (auto& entry : _objects)
	{
		for (auto& p : entry.second)
		{
			if (p.object == ptr)
				return p.identifiers[ptr->origin()];
		}
	}

	return 0;
}

void ObjectsCache::performUpdate()
{
	ObjectsCache& cache = *this;

	for (auto& entry : _objects)
	{
		for (auto& p : entry.second)
		{
			if (p.loader.valid() && p.object->canBeReloaded())
			{
				bool shouldReload = false;

				for (auto i : p.identifiers)
				{
					uint64_t prop = getFileProperty(i.first);
					if (prop != i.second)
					{
						i.second = prop;
						shouldReload = true;
						break;
					}
				}

				if (shouldReload)
					p.loader->reloadObject(p.object, cache);
			}
		}
	}
}

void ObjectsCache::report()
{
	log::info("[ObjectsCache] Contains %llu objects", static_cast<uint64_t>(_objects.size()));
}
<commit_msg>fix in ObjectsCache<commit_after>/*
 * This file is part of `et engine`
 * Copyright 2009-2015 by Sergey Reznik
 * Please, modify content only if you know what are you doing.
 *
 */

#include <et/core/objectscache.h>

using namespace et;

ObjectsCache::ObjectsCache() :
	_updateTime(0.0f)
{
}

ObjectsCache::~ObjectsCache()
{
	clear();
}

void ObjectsCache::manage(const LoadableObject::Pointer& o, const ObjectLoader::Pointer& loader)
{
	if (o.valid() && o->canBeReloaded())
	{
		CriticalSectionScope lock(_lock);

		if (_objects.count(o->origin()) > 0)
		{
			ObjectPropertyList& list = _objects[o->origin()];
			list.push_back(ObjectProperty(o, loader));
			ObjectProperty& newObject = list.back();
			newObject.identifiers[o->origin()] = getFileProperty(o->origin());
			for (auto& s : o->distributedOrigins())
				newObject.identifiers[s] = getFileProperty(s);
		}
		else
		{
			ObjectPropertyList newList(1, ObjectProperty(o, loader));
			ObjectProperty& newObject = newList.back();
			newObject.identifiers[o->origin()] = getFileProperty(o->origin());
			for (auto& s : o->distributedOrigins())
				newObject.identifiers[s] = getFileProperty(s);
			_objects.insert(std::make_pair(o->origin(), newList));
		}
	}
	else
	{
		log::warning("[ObjectsCache] Trying to manage invalid object");
	}
}

std::vector<LoadableObject::Pointer> ObjectsCache::findObjects(const std::string& key)
{
	CriticalSectionScope lock(_lock);
	auto i = _objects.find(key);
	if (i == _objects.end())
		return std::vector<LoadableObject::Pointer>();

	std::vector<LoadableObject::Pointer> result;

	for (auto prop : i->second)
		result.push_back(prop.object);

	return result;
}

LoadableObject::Pointer ObjectsCache::findAnyObject(const std::string& key, uint64_t* property)
{
	CriticalSectionScope lock(_lock);

	auto i = _objects.find(key);
	if (i == _objects.end())
	{
		if (property)
			*property = 0;

		return  LoadableObject::Pointer();
	}
	else
	{
		if (property)
			*property = i->second.front().identifiers[key];

		return i->second.front().object;
	}
}

void ObjectsCache::discard(const LoadableObject::Pointer& o)
{
	if (o.valid())
	{
		CriticalSectionScope lock(_lock);
		if (_objects.count(o->origin()) == 0) return;

		ObjectPropertyList& list = _objects[o->origin()];
		for (auto i = list.begin(), e = list.end(); i != e; ++i)
		{
			if (i->object == o)
			{
				list.erase(i);
				break;
			}
		}

		if (list.empty())
			_objects.erase(o->origin());
	}
}

void ObjectsCache::clear()
{
	CriticalSectionScope lock(_lock);
	_objects.clear();
}

void ObjectsCache::flush()
{
	CriticalSectionScope lock(_lock);

	size_t objectsErased = 0;

	for (auto& lv : _objects)
	{
		auto obj = lv.second.begin();
		while (obj != lv.second.end())
		{
			if (obj->object->atomicCounterValue() == 1)
			{
				obj = lv.second.erase(obj);
				++objectsErased;
			}
			else
			{
				++obj;
			}
		}
	}

	auto i = _objects.begin();
	while (i != _objects.end())
	{
		if (i->second.empty())
		{
			i = _objects.erase(i);
		}
		else
		{
			++i;
		}
	}

	if (objectsErased > 0)
		log::info("[ObjectsCache] %llu objects flushed.", static_cast<uint64_t>(objectsErased));
}

void ObjectsCache::startMonitoring()
{
	startUpdates();
}

void ObjectsCache::stopMonitoring()
{
	cancelUpdates();
}

void ObjectsCache::update(float t)
{
	static const float updateInterval = 0.5f;

	if (_updateTime == 0.0f)
		_updateTime = t;

	float dt = t - _updateTime;

	if (dt > updateInterval)
	{
		performUpdate();
		_updateTime = t;
	}
}

uint64_t ObjectsCache::getFileProperty(const std::string& p)
{
	return getFileDate(p);
}

uint64_t ObjectsCache::getObjectProperty(LoadableObject::Pointer ptr)
{
	CriticalSectionScope lock(_lock);

	for (auto& entry : _objects)
	{
		for (auto& p : entry.second)
		{
			if (p.object == ptr)
				return p.identifiers[ptr->origin()];
		}
	}

	return 0;
}

void ObjectsCache::performUpdate()
{
	ObjectsCache& cache = *this;

	for (auto& entry : _objects)
	{
		for (auto& p : entry.second)
		{
			if (p.loader.valid() && p.object->canBeReloaded())
			{
				bool shouldReload = false;

				const auto& origin = p.object->origin();
				uint64_t originProp = getFileProperty(origin);
				if (p.identifiers[origin] != originProp)
				{
					p.identifiers[origin] = originProp;
					shouldReload = true;
				}
				else
				{
					for (const auto& dOrigin : p.object->distributedOrigins())
					{
						auto prop = getFileProperty(dOrigin);
						if (p.identifiers[dOrigin] != prop)
						{
							p.identifiers[dOrigin] = prop;
							shouldReload = true;
							break;
						}
					}
				}

				if (shouldReload)
					p.loader->reloadObject(p.object, cache);
			}
		}
	}
}

void ObjectsCache::report()
{
	log::info("[ObjectsCache] Contains %llu objects", static_cast<uint64_t>(_objects.size()));
}
<|endoftext|>