<commit_before>
#ifndef __ARCH_MOCK_IO_HPP__
#define __ARCH_MOCK_IO_HPP__

#include "containers/segmented_vector.hpp"
#include "utils2.hpp"
#include <stdlib.h>

struct mock_iocallback_t {
    virtual void on_io_complete(event_t *event) = 0;
    virtual ~mock_iocallback_t() {}
};

template<class inner_io_config_t>
class mock_direct_file_t
{
public:
    enum mode_t {
        mode_read = 1 << 0,
        mode_write = 1 << 1,
        mode_create = 1 << 2
    };

    mock_direct_file_t(const char *path, int mode) {
        int mode2 = 0;
        if (mode & mode_read) mode2 |= inner_io_config_t::direct_file_t::mode_read;
        if (mode & mode_write) mode2 |= inner_io_config_t::direct_file_t::mode_write;
        if (mode & mode_create) mode2 |= inner_io_config_t::direct_file_t::mode_create;
        inner_file = new typename inner_io_config_t::direct_file_t(path, mode2);

        if (inner_file->is_block_device()) {
            fail_due_to_user_error(
                "Using mock_direct_file_t with a block device is a really bad idea because it "
                "reads the entire contents of the underlying file into memory, which could be "
                "a lot for a block device.");
        }

        set_size(inner_file->get_size());
        for (unsigned i = 0; i < get_size() / DEVICE_BLOCK_SIZE; i++) {
            inner_file->read_blocking(i*DEVICE_BLOCK_SIZE, DEVICE_BLOCK_SIZE, blocks[i].data);
        }
    }

    bool exists() {
        return inner_file->exists();
    }

    bool is_block_device() {
        return false;
    }

    uint64_t get_size() {
        return blocks.get_size() * DEVICE_BLOCK_SIZE;
    }

    void set_size(size_t size) {
        assert(size % DEVICE_BLOCK_SIZE == 0);
        blocks.set_size(size / DEVICE_BLOCK_SIZE);
    }

    void set_size_at_least(size_t size) {
        if (get_size() < size) {
            size_t actual_size = size + randint(10) * DEVICE_BLOCK_SIZE;
            set_size(actual_size);
        }
    }

    /* These always return 'false'; the reason they return bool instead of void
    is for consistency with other asynchronous-callback methods */
    bool read_async(size_t offset, size_t length, void *buf, mock_iocallback_t *cb) {
        read_blocking(offset, length, buf);
        random_delay(cb, &mock_iocallback_t::on_io_complete, (event_t*)NULL);
        return false;
    }

    bool write_async(size_t offset, size_t length, void *buf, mock_iocallback_t *cb) {
        write_blocking(offset, length, buf);
        random_delay(cb, &mock_iocallback_t::on_io_complete, (event_t*)NULL);
        return false;
    }

    void read_blocking(size_t offset, size_t length, void *buf) {
        verify(offset, length, buf);
        for (unsigned i = 0; i < length / DEVICE_BLOCK_SIZE; i += 1) {
            memcpy((char*)buf + i*DEVICE_BLOCK_SIZE, blocks[offset/DEVICE_BLOCK_SIZE + i].data, DEVICE_BLOCK_SIZE);
        }
    }

    void write_blocking(size_t offset, size_t length, void *buf) {
        verify(offset, length, buf);
        for (unsigned i = 0; i < length / DEVICE_BLOCK_SIZE; i += 1) {
            memcpy(blocks[offset/DEVICE_BLOCK_SIZE + i].data, (char*)buf + i*DEVICE_BLOCK_SIZE, DEVICE_BLOCK_SIZE);
        }
    }

    ~mock_direct_file_t() {
        inner_file->set_size(get_size());
        for (unsigned i = 0; i < get_size() / DEVICE_BLOCK_SIZE; i++) {
            inner_file->write_blocking(i*DEVICE_BLOCK_SIZE, DEVICE_BLOCK_SIZE, blocks[i].data);
        }

        delete inner_file;
    }

private:
    typename inner_io_config_t::direct_file_t *inner_file;

    struct block_t {
        char *data;

        block_t() {
            data = (char*)malloc_aligned(DEVICE_BLOCK_SIZE, DEVICE_BLOCK_SIZE);

            // Initialize to either random data or zeroes, choosing at random
            char d = randint(2) ? 0 : randint(0x100);
            memset(data, d, DEVICE_BLOCK_SIZE);
        }

        ~block_t() {
            free((void*)data);
        }
    };
    segmented_vector_t<block_t, 10*GIGABYTE/DEVICE_BLOCK_SIZE> blocks;

    void verify(size_t offset, size_t length, void *buf) {
        assert(buf);
        assert(offset + length <= get_size());
        assert((intptr_t)buf % DEVICE_BLOCK_SIZE == 0);
        assert(offset % DEVICE_BLOCK_SIZE == 0);
        assert(length % DEVICE_BLOCK_SIZE == 0);
    }
};

#endif /* __ARCH_MOCK_IO_HPP__ */
<commit_msg>Fixing mock io layer to work properly with file permissions and truncation in all cases (db creation, loading existing file, force recreation, etc.)<commit_after>
#ifndef __ARCH_MOCK_IO_HPP__
#define __ARCH_MOCK_IO_HPP__

#include "containers/segmented_vector.hpp"
#include "utils2.hpp"
#include <stdlib.h>

struct mock_iocallback_t {
    virtual void on_io_complete(event_t *event) = 0;
    virtual ~mock_iocallback_t() {}
};

template<class inner_io_config_t>
class mock_direct_file_t
{
public:
    enum mode_t {
        mode_read = 1 << 0,
        mode_write = 1 << 1,
        mode_create = 1 << 2
    };

    mock_direct_file_t(const char *path, int mode) {
        int mode2 = 0;
        if (mode & mode_read) mode2 |= inner_io_config_t::direct_file_t::mode_read;
        // We always enable writing because the mock layer does
        // truncation on exit
        mode2 |= inner_io_config_t::direct_file_t::mode_write;
        if (mode & mode_create) mode2 |= inner_io_config_t::direct_file_t::mode_create;
        inner_file = new typename inner_io_config_t::direct_file_t(path, mode2);

        if (inner_file->is_block_device()) {
            fail_due_to_user_error(
                "Using mock_direct_file_t with a block device is a really bad idea because it "
                "reads the entire contents of the underlying file into memory, which could be "
                "a lot for a block device.");
        }

        set_size(inner_file->get_size());
        for (unsigned i = 0; i < get_size() / DEVICE_BLOCK_SIZE; i++) {
            inner_file->read_blocking(i*DEVICE_BLOCK_SIZE, DEVICE_BLOCK_SIZE, blocks[i].data);
        }
    }

    bool exists() {
        return inner_file->exists();
    }

    bool is_block_device() {
        return false;
    }

    uint64_t get_size() {
        return blocks.get_size() * DEVICE_BLOCK_SIZE;
    }

    void set_size(size_t size) {
        assert(size % DEVICE_BLOCK_SIZE == 0);
        blocks.set_size(size / DEVICE_BLOCK_SIZE);
    }

    void set_size_at_least(size_t size) {
        if (get_size() < size) {
            size_t actual_size = size + randint(10) * DEVICE_BLOCK_SIZE;
            set_size(actual_size);
        }
    }

    /* These always return 'false'; the reason they return bool instead of void
    is for consistency with other asynchronous-callback methods */
    bool read_async(size_t offset, size_t length, void *buf, mock_iocallback_t *cb) {
        read_blocking(offset, length, buf);
        random_delay(cb, &mock_iocallback_t::on_io_complete, (event_t*)NULL);
        return false;
    }

    bool write_async(size_t offset, size_t length, void *buf, mock_iocallback_t *cb) {
        write_blocking(offset, length, buf);
        random_delay(cb, &mock_iocallback_t::on_io_complete, (event_t*)NULL);
        return false;
    }

    void read_blocking(size_t offset, size_t length, void *buf) {
        verify(offset, length, buf);
        for (unsigned i = 0; i < length / DEVICE_BLOCK_SIZE; i += 1) {
            memcpy((char*)buf + i*DEVICE_BLOCK_SIZE, blocks[offset/DEVICE_BLOCK_SIZE + i].data, DEVICE_BLOCK_SIZE);
        }
    }

    void write_blocking(size_t offset, size_t length, void *buf) {
        verify(offset, length, buf);
        for (unsigned i = 0; i < length / DEVICE_BLOCK_SIZE; i += 1) {
            memcpy(blocks[offset/DEVICE_BLOCK_SIZE + i].data, (char*)buf + i*DEVICE_BLOCK_SIZE, DEVICE_BLOCK_SIZE);
        }
    }

    ~mock_direct_file_t() {
        if(exists()) {
            inner_file->set_size(get_size());
        }
        for (unsigned i = 0; i < get_size() / DEVICE_BLOCK_SIZE; i++) {
            inner_file->write_blocking(i*DEVICE_BLOCK_SIZE, DEVICE_BLOCK_SIZE, blocks[i].data);
        }

        delete inner_file;
    }

private:
    typename inner_io_config_t::direct_file_t *inner_file;

    struct block_t {
        char *data;

        block_t() {
            data = (char*)malloc_aligned(DEVICE_BLOCK_SIZE, DEVICE_BLOCK_SIZE);

            // Initialize to either random data or zeroes, choosing at random
            char d = randint(2) ? 0 : randint(0x100);
            memset(data, d, DEVICE_BLOCK_SIZE);
        }

        ~block_t() {
            free((void*)data);
        }
    };
    segmented_vector_t<block_t, 10*GIGABYTE/DEVICE_BLOCK_SIZE> blocks;

    void verify(size_t offset, size_t length, void *buf) {
        assert(buf);
        assert(offset + length <= get_size());
        assert((intptr_t)buf % DEVICE_BLOCK_SIZE == 0);
        assert(offset % DEVICE_BLOCK_SIZE == 0);
        assert(length % DEVICE_BLOCK_SIZE == 0);
    }
};

#endif /* __ARCH_MOCK_IO_HPP__ */
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: wall.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: vg $ $Date: 2007-04-11 18:16:43 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _SV_WALL_HXX
#define _SV_WALL_HXX

#ifndef _SV_SV_H
#include <vcl/sv.h>
#endif
#ifndef _VCL_DLLAPI_H
#include <vcl/dllapi.h>
#endif

#ifndef _TOOLS_COLOR_HXX
#include <tools/color.hxx>
#endif

class Rectangle;
class Gradient;
class BitmapEx;
class ImplWallpaper;

// -------------------
// - Wallpaper-Types -
// -------------------

#define WALLPAPER_NULL                  WallpaperStyle_NULL
#define WALLPAPER_TILE                  WallpaperStyle_TILE
#define WALLPAPER_CENTER                WallpaperStyle_CENTER
#define WALLPAPER_SCALE                 WallpaperStyle_SCALE
#define WALLPAPER_TOPLEFT               WallpaperStyle_TOPLEFT
#define WALLPAPER_TOP                   WallpaperStyle_TOP
#define WALLPAPER_TOPRIGHT              WallpaperStyle_TOPRIGHT
#define WALLPAPER_LEFT                  WallpaperStyle_LEFT
#define WALLPAPER_RIGHT                 WallpaperStyle_RIGHT
#define WALLPAPER_BOTTOMLEFT            WallpaperStyle_BOTTOMLEFT
#define WALLPAPER_BOTTOM                WallpaperStyle_BOTTOM
#define WALLPAPER_BOTTOMRIGHT           WallpaperStyle_BOTTOMRIGHT
#define WALLPAPER_APPLICATIONGRADIENT   WallpaperStyle_APPLICATIONGRADIENT
#define WALLPAPER_FORCE_EQUAL_SIZE      WallpaperStyle_FORCE_EQUAL_SIZE

#ifndef ENUM_WALLPAPERSTYLE_DECLARED
#define ENUM_WALLPAPERSTYLE_DECLARED

enum WallpaperStyle
{
    WALLPAPER_NULL,
    WALLPAPER_TILE,
    WALLPAPER_CENTER,
    WALLPAPER_SCALE,
    WALLPAPER_TOPLEFT,
    WALLPAPER_TOP,
    WALLPAPER_TOPRIGHT,
    WALLPAPER_LEFT,
    WALLPAPER_RIGHT,
    WALLPAPER_BOTTOMLEFT,
    WALLPAPER_BOTTOM,
    WALLPAPER_BOTTOMRIGHT,
    WALLPAPER_APPLICATIONGRADIENT,          // defines a gradient that internally covers the whole application
                                            // and uses a color derived from the face color
    WALLPAPER_FORCE_EQUAL_SIZE = 0x7fffffff
};

#endif

// -------------
// - Wallpaper -
// -------------

class VCL_DLLPUBLIC Wallpaper
{
private:
    ImplWallpaper*  mpImplWallpaper;

    SAL_DLLPRIVATE void           ImplMakeUnique( BOOL bReleaseCache = TRUE );
    SAL_DLLPRIVATE Gradient       ImplGetApplicationGradient() const;

//#if 0 // _SOLAR__PRIVATE
public:
    SAL_DLLPRIVATE ImplWallpaper* ImplGetImpWallpaper() const { return mpImplWallpaper; }
//#endif

public:
                    Wallpaper();
                    Wallpaper( const Wallpaper& rWallpaper );
                    Wallpaper( const Color& rColor );
                    Wallpaper( const BitmapEx& rBmpEx );
                    Wallpaper( const Gradient& rGradient );
                    ~Wallpaper();

    void            SetColor( const Color& rColor );
    const Color&    GetColor() const;

    void            SetStyle( WallpaperStyle eStyle );
    WallpaperStyle  GetStyle() const;

    void            SetBitmap( const BitmapEx& rBitmap );
    void            SetBitmap();
    BitmapEx        GetBitmap() const;
    BOOL            IsBitmap() const;

    void            SetGradient( const Gradient& rGradient );
    void            SetGradient();
    Gradient        GetGradient() const;
    BOOL            IsGradient() const;

    void            SetRect( const Rectangle& rRect );
    void            SetRect();
    Rectangle       GetRect() const;
    BOOL            IsRect() const;

    BOOL            IsFixed() const;
    BOOL            IsScrollable() const;

    Wallpaper&      operator=( const Wallpaper& rWallpaper );
    BOOL            operator==( const Wallpaper& rWallpaper ) const;
    BOOL            operator!=( const Wallpaper& rWallpaper ) const
                        { return !(Wallpaper::operator==( rWallpaper )); }
    BOOL            IsSameInstance( const Wallpaper& rWallpaper ) const
                        { return (mpImplWallpaper == rWallpaper.mpImplWallpaper); }

    friend VCL_DLLPUBLIC SvStream& operator>>( SvStream& rIStm, Wallpaper& rWallpaper );
    friend VCL_DLLPUBLIC SvStream& operator<<( SvStream& rOStm, const Wallpaper& rWallpaper );
};

#endif  // _SV_WALL_HXX
<commit_msg>INTEGRATION: CWS changefileheader (1.2.320); FILE MERGED 2008/04/01 16:05:23 thb 1.2.320.3: #i85898# Stripping all external header guards 2008/04/01 13:01:19 thb 1.2.320.2: #i85898# Stripping all external header guards 2008/03/28 15:44:19 rt 1.2.320.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: wall.hxx,v $
 * $Revision: 1.3 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _SV_WALL_HXX
#define _SV_WALL_HXX

#include <vcl/sv.h>
#include <vcl/dllapi.h>
#include <tools/color.hxx>

class Rectangle;
class Gradient;
class BitmapEx;
class ImplWallpaper;

// -------------------
// - Wallpaper-Types -
// -------------------

#define WALLPAPER_NULL                  WallpaperStyle_NULL
#define WALLPAPER_TILE                  WallpaperStyle_TILE
#define WALLPAPER_CENTER                WallpaperStyle_CENTER
#define WALLPAPER_SCALE                 WallpaperStyle_SCALE
#define WALLPAPER_TOPLEFT               WallpaperStyle_TOPLEFT
#define WALLPAPER_TOP                   WallpaperStyle_TOP
#define WALLPAPER_TOPRIGHT              WallpaperStyle_TOPRIGHT
#define WALLPAPER_LEFT                  WallpaperStyle_LEFT
#define WALLPAPER_RIGHT                 WallpaperStyle_RIGHT
#define WALLPAPER_BOTTOMLEFT            WallpaperStyle_BOTTOMLEFT
#define WALLPAPER_BOTTOM                WallpaperStyle_BOTTOM
#define WALLPAPER_BOTTOMRIGHT           WallpaperStyle_BOTTOMRIGHT
#define WALLPAPER_APPLICATIONGRADIENT   WallpaperStyle_APPLICATIONGRADIENT
#define WALLPAPER_FORCE_EQUAL_SIZE      WallpaperStyle_FORCE_EQUAL_SIZE

#ifndef ENUM_WALLPAPERSTYLE_DECLARED
#define ENUM_WALLPAPERSTYLE_DECLARED

enum WallpaperStyle
{
    WALLPAPER_NULL,
    WALLPAPER_TILE,
    WALLPAPER_CENTER,
    WALLPAPER_SCALE,
    WALLPAPER_TOPLEFT,
    WALLPAPER_TOP,
    WALLPAPER_TOPRIGHT,
    WALLPAPER_LEFT,
    WALLPAPER_RIGHT,
    WALLPAPER_BOTTOMLEFT,
    WALLPAPER_BOTTOM,
    WALLPAPER_BOTTOMRIGHT,
    WALLPAPER_APPLICATIONGRADIENT,          // defines a gradient that internally covers the whole application
                                            // and uses a color derived from the face color
    WALLPAPER_FORCE_EQUAL_SIZE = 0x7fffffff
};

#endif

// -------------
// - Wallpaper -
// -------------

class VCL_DLLPUBLIC Wallpaper
{
private:
    ImplWallpaper*  mpImplWallpaper;

    SAL_DLLPRIVATE void           ImplMakeUnique( BOOL bReleaseCache = TRUE );
    SAL_DLLPRIVATE Gradient       ImplGetApplicationGradient() const;

//#if 0 // _SOLAR__PRIVATE
public:
    SAL_DLLPRIVATE ImplWallpaper* ImplGetImpWallpaper() const { return mpImplWallpaper; }
//#endif

public:
                    Wallpaper();
                    Wallpaper( const Wallpaper& rWallpaper );
                    Wallpaper( const Color& rColor );
                    Wallpaper( const BitmapEx& rBmpEx );
                    Wallpaper( const Gradient& rGradient );
                    ~Wallpaper();

    void            SetColor( const Color& rColor );
    const Color&    GetColor() const;

    void            SetStyle( WallpaperStyle eStyle );
    WallpaperStyle  GetStyle() const;

    void            SetBitmap( const BitmapEx& rBitmap );
    void            SetBitmap();
    BitmapEx        GetBitmap() const;
    BOOL            IsBitmap() const;

    void            SetGradient( const Gradient& rGradient );
    void            SetGradient();
    Gradient        GetGradient() const;
    BOOL            IsGradient() const;

    void            SetRect( const Rectangle& rRect );
    void            SetRect();
    Rectangle       GetRect() const;
    BOOL            IsRect() const;

    BOOL            IsFixed() const;
    BOOL            IsScrollable() const;

    Wallpaper&      operator=( const Wallpaper& rWallpaper );
    BOOL            operator==( const Wallpaper& rWallpaper ) const;
    BOOL            operator!=( const Wallpaper& rWallpaper ) const
                        { return !(Wallpaper::operator==( rWallpaper )); }
    BOOL            IsSameInstance( const Wallpaper& rWallpaper ) const
                        { return (mpImplWallpaper == rWallpaper.mpImplWallpaper); }

    friend VCL_DLLPUBLIC SvStream& operator>>( SvStream& rIStm, Wallpaper& rWallpaper );
    friend VCL_DLLPUBLIC SvStream& operator<<( SvStream& rOStm, const Wallpaper& rWallpaper );
};

#endif  // _SV_WALL_HXX
<|endoftext|>


<commit_before>#include "v8monoctx.h"

static v8::Isolate* isolate;
static v8::Persistent<v8::Context> context;
static std::map<std::string, time_t> ScriptModified;
static std::map<std::string, PERSISTENT_COPYABLE> ScriptCached;

static std::string GlobalData;
static std::vector<std::string> GlobalError;

// Profiler functions
void StartProfile(struct timeval *t1) {
   	gettimeofday(t1, NULL);
}

double StopProfile(struct timeval *t1) {
	struct timeval t2;
  	gettimeofday(&t2, NULL);
  	return (((t2.tv_sec - t1->tv_sec) * 1000000) + (t2.tv_usec - t1->tv_usec)) / 1000000.0;
}

// Just convert to string
const char* ToCString(const v8::String::Utf8Value& value) {
	return *value ? *value : "<string conversion failed>";
}

// Reads a file into a string.
std::string ReadFile(std::string name) {
	FILE* file = fopen(name.c_str(), "rb");
	if (file == NULL) return std::string();

	fseek(file, 0, SEEK_END);
	int size = ftell(file);
	rewind(file);

	char* chars = new char[size + 1];
	chars[size] = '\0';
	for (int i = 0; i < size;) {
		int read = static_cast<int>(fread(&chars[i], 1, size - i, file));
		i += read;
	}
	fclose(file);

	std::string result(chars);
	delete[] chars;
	return result;
}

void ReportException(v8::TryCatch* try_catch) {
	v8::HandleScope handle_scope(isolate);
	v8::String::Utf8Value exception(try_catch->Exception());

	std::string exception_string( ToCString(exception) );
	v8::Handle<v8::Message> message = try_catch->Message();

	if (message.IsEmpty()) {
		// V8 didn't provide any extra information about this error; just
		// print the exception.

		GlobalError.push_back(exception_string);
	} else {
		// Print (filename):(line number): (message)\n(sourceline)
		v8::String::Utf8Value filename(message->GetScriptResourceName());
		v8::String::Utf8Value sourceline(message->GetSourceLine());

		std::string _err( ToCString(filename) );
		std::string _source( ToCString(sourceline) );

		std::ostringstream linenum;
		linenum << message->GetLineNumber();

		_err += ":";
		_err += linenum.str();
		_err += ": ";
		_err += exception_string;
		_err += "\n";
		_err += _source;

		GlobalError.push_back(_err);

/*
		// Print wavy underline (GetUnderline is deprecated).
		int start = message->GetStartColumn();
		for (int i = 0; i < start; i++) {
			fprintf(stderr, " ");
		}
		int end = message->GetEndColumn();
		for (int i = start; i < end; i++) {
			fprintf(stderr, "^");
		}
		fprintf(stderr, "\n");
		v8::String::Utf8Value stack_trace(try_catch->StackTrace());
		if (stack_trace.length() > 0) {
			const char* stack_trace_string = ToCString(stack_trace);
			fprintf(stderr, "%s\n", stack_trace_string);
		}
*/
	}
}

// Global function
void DataFetch(const v8::FunctionCallbackInfo<v8::Value>& args) {
	// We will be creating temporary handles so we use a handle scope.
	v8::HandleScope handle_scope(args.GetIsolate());

	args.GetReturnValue().Set(
		v8::String::NewFromUtf8(args.GetIsolate(), GlobalData.c_str())
	);
}

// Global function
void ConsoleError(const v8::FunctionCallbackInfo<v8::Value>& args) {
	for (int i = 0; i < args.Length(); i++) {
		v8::HandleScope handle_scope(args.GetIsolate());
		v8::String::Utf8Value str(args[i]);

		std::string _err( ToCString(str) );
		GlobalError.push_back(_err);
	}
}

std::vector<std::string> GetErrors (void) {
	return GlobalError;
}

bool LoadFile(monocfg * cfg, std::string fname) {
	GlobalError.clear();

	cfg->run_idle_notification_loop_time = 0;
	cfg->run_low_memory_notification_time = 0;
	cfg->exec_time = 0;
	cfg->compile_time = 0;

	if (isolate == NULL) {
		// Get the default Isolate created at startup
		isolate = v8::Isolate::GetCurrent();

		// Create a stack-allocated handle scope
		v8::HandleScope handle_scope(isolate);

		if (strlen(cfg->cmd_args) > 0) {
			v8::V8::SetFlagsFromString(cfg->cmd_args, strlen(cfg->cmd_args));
		}

		// Global objects
		v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
		global->Set(v8::String::NewFromUtf8(isolate, "__dataFetch"), v8::FunctionTemplate::New(isolate, DataFetch));
		global->Set(v8::String::NewFromUtf8(isolate, "__errorLog"), v8::FunctionTemplate::New(isolate, ConsoleError));

		// Create a new context
		v8::Handle<v8::Context> ctx = v8::Context::New(isolate, NULL, global);
		context.Reset(isolate, ctx);

		if (context.IsEmpty()) {
			std::string _err("Error creating context");
			GlobalError.push_back(_err);

			return false;
		}
		ctx->Enter();
	}

	v8::HandleScope handle_scope(isolate);
	v8::TryCatch try_catch;

	std::string key = fname;

	// Get file stat
	struct stat stat_buf;
	if (cfg->watch_templates) {
		int rc = stat(fname.c_str(), &stat_buf);
		if (rc != 0) {
			std::string _err("Error opening file ");
			_err += fname;
			_err += ": ";
			_err += strerror(errno);

			GlobalError.push_back(_err);

			return false;
		}
	}

	v8::Local<v8::Script> script;
	if (ScriptCached.find(key) == ScriptCached.end() || (cfg->watch_templates && ScriptModified[key] != stat_buf.st_mtime)) {
/*
		if (ScriptCached.find(key) == ScriptCached.end()) {
			fprintf(stderr, "New file: %s\n", fname.c_str());
		}
		else {
			fprintf(stderr, "File modified: %s\n", fname.c_str());
		}
*/
		// Read new file
		std::string file = ReadFile(fname);
		if (file.size() == 0) {
			std::string _err("File not exists or empty: ");
			_err += fname;

			GlobalError.push_back(_err);
			return false;
		}

		std::string file_append = file;
		v8::Handle<v8::String> source = v8::String::NewFromUtf8(isolate, file_append.c_str());
		v8::Handle<v8::String> ffn = v8::String::NewFromUtf8(isolate, fname.c_str());

		// Origin
		v8::Handle<v8::Integer> line = v8::Integer::New(isolate, 0);
		v8::Handle<v8::Integer> column = v8::Integer::New(isolate, 0);
		v8::ScriptOrigin origin(ffn, line, column);

		struct timeval t1; StartProfile(&t1);
			script = v8::Script::Compile(source, &origin);
		cfg->compile_time += StopProfile(&t1);

		if (script.IsEmpty()) {
			ReportException(&try_catch);
			return false;
		}

		PERSISTENT_COPYABLE pscript;

		ScriptCached.insert( std::pair<std::string, PERSISTENT_COPYABLE>(key, pscript) );
		ScriptCached[key].Reset(isolate, script);
		ScriptModified[key] = stat_buf.st_mtime;
	}
	else {
		script = v8::Local<v8::Script>::New(isolate, ScriptCached[key]);
	}

	v8::Handle<v8::Value> result;
	struct timeval t1; StartProfile(&t1);
		result = script->Run();
	cfg->exec_time += StopProfile(&t1);

	if (result.IsEmpty()) {
		assert(try_catch.HasCaught());
		ReportException(&try_catch);
		return false;
	}

	// No errors
	assert(!try_catch.HasCaught());
	return true;
}

bool ExecuteFile(monocfg * cfg, std::string fname, std::string append, std::string* json, std::string* out) {
	GlobalError.clear();

	++cfg->request_num;

	cfg->run_idle_notification_loop_time = 0;
	cfg->run_low_memory_notification_time = 0;
	cfg->exec_time = 0;
	cfg->compile_time = 0;

	if (isolate == NULL) {
		// Get the default Isolate created at startup
		isolate = v8::Isolate::GetCurrent();

		// Create a stack-allocated handle scope
		v8::HandleScope handle_scope(isolate);

		if (strlen(cfg->cmd_args) > 0) {
			v8::V8::SetFlagsFromString(cfg->cmd_args, strlen(cfg->cmd_args));
		}

		// Global objects
		v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
		global->Set(v8::String::NewFromUtf8(isolate, "__dataFetch"), v8::FunctionTemplate::New(isolate, DataFetch));
		global->Set(v8::String::NewFromUtf8(isolate, "__errorLog"), v8::FunctionTemplate::New(isolate, ConsoleError));

		// Create a new context
		v8::Handle<v8::Context> ctx = v8::Context::New(isolate, NULL, global);
		context.Reset(isolate, ctx);

		if (context.IsEmpty()) {
			std::string _err("Error creating context");
			GlobalError.push_back(_err);

			return false;
		}
		ctx->Enter();
	}

	v8::HandleScope handle_scope(isolate);
	v8::TryCatch try_catch;

	if (json != NULL) {
		GlobalData.assign(*json);
	}

	std::string key = fname + ' ' + append;

	// Get file stat
	struct stat stat_buf;
	if (cfg->watch_templates) {
		int rc = stat(fname.c_str(), &stat_buf);
		if (rc != 0) {
			std::string _err("Error opening file ");
			_err += fname;
			_err += ": ";
			_err += strerror(errno);

			GlobalError.push_back(_err);

			return false;
		}
	}

	v8::Local<v8::Script> script;
	if (ScriptCached.find(key) == ScriptCached.end() || (cfg->watch_templates && ScriptModified[key] != stat_buf.st_mtime)) {
/*
		if (ScriptCached.find(key) == ScriptCached.end()) {
			fprintf(stderr, "New file: %s\n", fname.c_str());
		}
		else {
			fprintf(stderr, "File modified: %s\n", fname.c_str());
		}
*/
		// Read new file
		std::string file = ReadFile(fname);
		if (file.size() == 0) {
			std::string _err("File not exists or empty: ");
			_err += fname;

			GlobalError.push_back(_err);
			return false;
		}

		std::string file_append = file + append;
		v8::Handle<v8::String> source = v8::String::NewFromUtf8(isolate, file_append.c_str());
		v8::Handle<v8::String> ffn = v8::String::NewFromUtf8(isolate, fname.c_str());

		// Origin
		v8::Handle<v8::Integer> line = v8::Integer::New(isolate, 0);
		v8::Handle<v8::Integer> column = v8::Integer::New(isolate, 0);
		v8::ScriptOrigin origin(ffn, line, column);

		struct timeval t1; StartProfile(&t1);
			script = v8::Script::Compile(source, &origin);
		cfg->compile_time += StopProfile(&t1);

		if (script.IsEmpty()) {
			ReportException(&try_catch);
			return false;
		}

		PERSISTENT_COPYABLE pscript;

		ScriptCached.insert( std::pair<std::string, PERSISTENT_COPYABLE>(key, pscript) );
		ScriptCached[key].Reset(isolate, script);
		ScriptModified[key] = stat_buf.st_mtime;
	}
	else {
		script = v8::Local<v8::Script>::New(isolate, ScriptCached[key]);
	}

	v8::Handle<v8::Value> result;
	struct timeval t1; StartProfile(&t1);
		result = script->Run();
	cfg->exec_time += StopProfile(&t1);

	if (result.IsEmpty()) {
		assert(try_catch.HasCaught());
		ReportException(&try_catch);
		return false;
	}

	// No errors
	assert(!try_catch.HasCaught());
	if (!result->IsUndefined() && out != NULL) {
		v8::String::Utf8Value utf8(result);
		out->assign(*utf8, utf8.length());
	}

	// Try to call GC in a very simple way
	if (cfg->run_low_memory_notification > 0 && cfg->request_num % cfg->run_low_memory_notification == 0) {
		struct timeval t1;
		StartProfile(&t1);
			v8::V8::LowMemoryNotification();
		cfg->run_low_memory_notification_time = StopProfile(&t1);
	}

	// Another gc calling mechanism
	if (cfg->run_idle_notification_loop > 0 && cfg->request_num % cfg->run_idle_notification_loop == 0) {
		struct timeval t1;
		StartProfile(&t1);
			while(!v8::V8::IdleNotification()) {}
		cfg->run_idle_notification_loop_time = StopProfile(&t1);
	}

	return true;
}

void GetHeapStat(HeapSt * st) {
	v8::HeapStatistics hs;
	if (isolate == NULL) {return;}

	isolate->GetHeapStatistics(&hs);

	st->total_heap_size = hs.total_heap_size();
	st->total_heap_size_executable = hs.total_heap_size_executable();
	st->total_physical_size = hs.total_physical_size();
	st->used_heap_size = hs.used_heap_size();
	st->heap_size_limit = hs.heap_size_limit();
}

bool IdleNotification(int ms) {
	if (isolate == NULL) {return false;}
	return v8::V8::IdleNotification(ms);
}

void LowMemoryNotification() {
	if (isolate == NULL) {return;}
	v8::V8::LowMemoryNotification();
}

<commit_msg>Split maps<commit_after>#include "v8monoctx.h"

static v8::Isolate* isolate;
static v8::Persistent<v8::Context> context;

/* maps for caching templates (ExecuteFile) */
static std::map<std::string, time_t> ExecuteScriptModified;
static std::map<std::string, PERSISTENT_COPYABLE> ExecuteScriptCached;

/* maps for caching utilites (LoadFile) */
static std::map<std::string, time_t> LoadScriptModified;
static std::map<std::string, PERSISTENT_COPYABLE> LoadScriptCached;

static std::string GlobalData;
static std::vector<std::string> GlobalError;

// Profiler functions
void StartProfile(struct timeval *t1) {
   	gettimeofday(t1, NULL);
}

double StopProfile(struct timeval *t1) {
	struct timeval t2;
  	gettimeofday(&t2, NULL);
  	return (((t2.tv_sec - t1->tv_sec) * 1000000) + (t2.tv_usec - t1->tv_usec)) / 1000000.0;
}

// Just convert to string
const char* ToCString(const v8::String::Utf8Value& value) {
	return *value ? *value : "<string conversion failed>";
}

// Reads a file into a string.
std::string ReadFile(std::string name) {
	FILE* file = fopen(name.c_str(), "rb");
	if (file == NULL) return std::string();

	fseek(file, 0, SEEK_END);
	int size = ftell(file);
	rewind(file);

	char* chars = new char[size + 1];
	chars[size] = '\0';
	for (int i = 0; i < size;) {
		int read = static_cast<int>(fread(&chars[i], 1, size - i, file));
		i += read;
	}
	fclose(file);

	std::string result(chars);
	delete[] chars;
	return result;
}

void ReportException(v8::TryCatch* try_catch) {
	v8::HandleScope handle_scope(isolate);
	v8::String::Utf8Value exception(try_catch->Exception());

	std::string exception_string( ToCString(exception) );
	v8::Handle<v8::Message> message = try_catch->Message();

	if (message.IsEmpty()) {
		// V8 didn't provide any extra information about this error; just
		// print the exception.

		GlobalError.push_back(exception_string);
	} else {
		// Print (filename):(line number): (message)\n(sourceline)
		v8::String::Utf8Value filename(message->GetScriptResourceName());
		v8::String::Utf8Value sourceline(message->GetSourceLine());

		std::string _err( ToCString(filename) );
		std::string _source( ToCString(sourceline) );

		std::ostringstream linenum;
		linenum << message->GetLineNumber();

		_err += ":";
		_err += linenum.str();
		_err += ": ";
		_err += exception_string;
		_err += "\n";
		_err += _source;

		GlobalError.push_back(_err);

/*
		// Print wavy underline (GetUnderline is deprecated).
		int start = message->GetStartColumn();
		for (int i = 0; i < start; i++) {
			fprintf(stderr, " ");
		}
		int end = message->GetEndColumn();
		for (int i = start; i < end; i++) {
			fprintf(stderr, "^");
		}
		fprintf(stderr, "\n");
		v8::String::Utf8Value stack_trace(try_catch->StackTrace());
		if (stack_trace.length() > 0) {
			const char* stack_trace_string = ToCString(stack_trace);
			fprintf(stderr, "%s\n", stack_trace_string);
		}
*/
	}
}

// Global function
void DataFetch(const v8::FunctionCallbackInfo<v8::Value>& args) {
	// We will be creating temporary handles so we use a handle scope.
	v8::HandleScope handle_scope(args.GetIsolate());

	args.GetReturnValue().Set(
		v8::String::NewFromUtf8(args.GetIsolate(), GlobalData.c_str())
	);
}

// Global function
void ConsoleError(const v8::FunctionCallbackInfo<v8::Value>& args) {
	for (int i = 0; i < args.Length(); i++) {
		v8::HandleScope handle_scope(args.GetIsolate());
		v8::String::Utf8Value str(args[i]);

		std::string _err( ToCString(str) );
		GlobalError.push_back(_err);
	}
}

std::vector<std::string> GetErrors (void) {
	return GlobalError;
}

bool LoadFile(monocfg * cfg, std::string fname) {
	GlobalError.clear();

	cfg->run_idle_notification_loop_time = 0;
	cfg->run_low_memory_notification_time = 0;
	cfg->exec_time = 0;
	cfg->compile_time = 0;

	if (isolate == NULL) {
		// Get the default Isolate created at startup
		isolate = v8::Isolate::GetCurrent();

		// Create a stack-allocated handle scope
		v8::HandleScope handle_scope(isolate);

		if (strlen(cfg->cmd_args) > 0) {
			v8::V8::SetFlagsFromString(cfg->cmd_args, strlen(cfg->cmd_args));
		}

		// Global objects
		v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
		global->Set(v8::String::NewFromUtf8(isolate, "__dataFetch"), v8::FunctionTemplate::New(isolate, DataFetch));
		global->Set(v8::String::NewFromUtf8(isolate, "__errorLog"), v8::FunctionTemplate::New(isolate, ConsoleError));

		// Create a new context
		v8::Handle<v8::Context> ctx = v8::Context::New(isolate, NULL, global);
		context.Reset(isolate, ctx);

		if (context.IsEmpty()) {
			std::string _err("Error creating context");
			GlobalError.push_back(_err);

			return false;
		}
		ctx->Enter();
	}

	v8::HandleScope handle_scope(isolate);
	v8::TryCatch try_catch;

	std::string key = fname;

	// Get file stat
	struct stat stat_buf;
	if (cfg->watch_templates) {
		int rc = stat(fname.c_str(), &stat_buf);
		if (rc != 0) {
			std::string _err("Error opening file ");
			_err += fname;
			_err += ": ";
			_err += strerror(errno);

			GlobalError.push_back(_err);

			return false;
		}
	}

	v8::Local<v8::Script> script;
	if (LoadScriptCached.find(key) == LoadScriptCached.end() || (cfg->watch_templates && LoadScriptModified[key] != stat_buf.st_mtime)) {
/*
		if (LoadScriptCached.find(key) == LoadScriptCached.end()) {
			fprintf(stderr, "New file: %s\n", fname.c_str());
		}
		else {
			fprintf(stderr, "File modified: %s\n", fname.c_str());
		}
*/
		// Read new file
		std::string file = ReadFile(fname);
		if (file.size() == 0) {
			std::string _err("File not exists or empty: ");
			_err += fname;

			GlobalError.push_back(_err);
			return false;
		}

		std::string file_append = file;
		v8::Handle<v8::String> source = v8::String::NewFromUtf8(isolate, file_append.c_str());
		v8::Handle<v8::String> ffn = v8::String::NewFromUtf8(isolate, fname.c_str());

		// Origin
		v8::Handle<v8::Integer> line = v8::Integer::New(isolate, 0);
		v8::Handle<v8::Integer> column = v8::Integer::New(isolate, 0);
		v8::ScriptOrigin origin(ffn, line, column);

		struct timeval t1; StartProfile(&t1);
			script = v8::Script::Compile(source, &origin);
		cfg->compile_time += StopProfile(&t1);

		if (script.IsEmpty()) {
			ReportException(&try_catch);
			return false;
		}

		PERSISTENT_COPYABLE pscript;

		LoadScriptCached.insert( std::pair<std::string, PERSISTENT_COPYABLE>(key, pscript) );
		LoadScriptCached[key].Reset(isolate, script);
		LoadScriptModified[key] = stat_buf.st_mtime;
	}
	else {
		script = v8::Local<v8::Script>::New(isolate, LoadScriptCached[key]);
	}

	v8::Handle<v8::Value> result;
	struct timeval t1; StartProfile(&t1);
		result = script->Run();
	cfg->exec_time += StopProfile(&t1);

	if (result.IsEmpty()) {
		assert(try_catch.HasCaught());
		ReportException(&try_catch);
		return false;
	}

	// No errors
	assert(!try_catch.HasCaught());
	return true;
}

bool ExecuteFile(monocfg * cfg, std::string fname, std::string append, std::string* json, std::string* out) {
	GlobalError.clear();

	++cfg->request_num;

	cfg->run_idle_notification_loop_time = 0;
	cfg->run_low_memory_notification_time = 0;
	cfg->exec_time = 0;
	cfg->compile_time = 0;

	if (isolate == NULL) {
		// Get the default Isolate created at startup
		isolate = v8::Isolate::GetCurrent();

		// Create a stack-allocated handle scope
		v8::HandleScope handle_scope(isolate);

		if (strlen(cfg->cmd_args) > 0) {
			v8::V8::SetFlagsFromString(cfg->cmd_args, strlen(cfg->cmd_args));
		}

		// Global objects
		v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
		global->Set(v8::String::NewFromUtf8(isolate, "__dataFetch"), v8::FunctionTemplate::New(isolate, DataFetch));
		global->Set(v8::String::NewFromUtf8(isolate, "__errorLog"), v8::FunctionTemplate::New(isolate, ConsoleError));

		// Create a new context
		v8::Handle<v8::Context> ctx = v8::Context::New(isolate, NULL, global);
		context.Reset(isolate, ctx);

		if (context.IsEmpty()) {
			std::string _err("Error creating context");
			GlobalError.push_back(_err);

			return false;
		}
		ctx->Enter();
	}

	v8::HandleScope handle_scope(isolate);
	v8::TryCatch try_catch;

	if (json != NULL) {
		GlobalData.assign(*json);
	}

	std::string key = fname + ' ' + append;

	// Get file stat
	struct stat stat_buf;
	if (cfg->watch_templates) {
		int rc = stat(fname.c_str(), &stat_buf);
		if (rc != 0) {
			std::string _err("Error opening file ");
			_err += fname;
			_err += ": ";
			_err += strerror(errno);

			GlobalError.push_back(_err);

			return false;
		}
	}

	v8::Local<v8::Script> script;
	if (ExecuteScriptCached.find(key) == ExecuteScriptCached.end() || (cfg->watch_templates && ExecuteScriptModified[key] != stat_buf.st_mtime)) {
/*
		if (ExecuteScriptCached.find(key) == ExecuteScriptCached.end()) {
			fprintf(stderr, "New file: %s\n", fname.c_str());
		}
		else {
			fprintf(stderr, "File modified: %s\n", fname.c_str());
		}
*/
		// Read new file
		std::string file = ReadFile(fname);
		if (file.size() == 0) {
			std::string _err("File not exists or empty: ");
			_err += fname;

			GlobalError.push_back(_err);
			return false;
		}

		std::string file_append = file + append;
		v8::Handle<v8::String> source = v8::String::NewFromUtf8(isolate, file_append.c_str());
		v8::Handle<v8::String> ffn = v8::String::NewFromUtf8(isolate, fname.c_str());

		// Origin
		v8::Handle<v8::Integer> line = v8::Integer::New(isolate, 0);
		v8::Handle<v8::Integer> column = v8::Integer::New(isolate, 0);
		v8::ScriptOrigin origin(ffn, line, column);

		struct timeval t1; StartProfile(&t1);
			script = v8::Script::Compile(source, &origin);
		cfg->compile_time += StopProfile(&t1);

		if (script.IsEmpty()) {
			ReportException(&try_catch);
			return false;
		}

		PERSISTENT_COPYABLE pscript;

		ExecuteScriptCached.insert( std::pair<std::string, PERSISTENT_COPYABLE>(key, pscript) );
		ExecuteScriptCached[key].Reset(isolate, script);
		ExecuteScriptModified[key] = stat_buf.st_mtime;
	}
	else {
		script = v8::Local<v8::Script>::New(isolate, ExecuteScriptCached[key]);
	}

	v8::Handle<v8::Value> result;
	struct timeval t1; StartProfile(&t1);
		result = script->Run();
	cfg->exec_time += StopProfile(&t1);

	if (result.IsEmpty()) {
		assert(try_catch.HasCaught());
		ReportException(&try_catch);
		return false;
	}

	// No errors
	assert(!try_catch.HasCaught());
	if (!result->IsUndefined() && out != NULL) {
		v8::String::Utf8Value utf8(result);
		out->assign(*utf8, utf8.length());
	}

	// Try to call GC in a very simple way
	if (cfg->run_low_memory_notification > 0 && cfg->request_num % cfg->run_low_memory_notification == 0) {
		struct timeval t1;
		StartProfile(&t1);
			v8::V8::LowMemoryNotification();
		cfg->run_low_memory_notification_time = StopProfile(&t1);
	}

	// Another gc calling mechanism
	if (cfg->run_idle_notification_loop > 0 && cfg->request_num % cfg->run_idle_notification_loop == 0) {
		struct timeval t1;
		StartProfile(&t1);
			while(!v8::V8::IdleNotification()) {}
		cfg->run_idle_notification_loop_time = StopProfile(&t1);
	}

	return true;
}

void GetHeapStat(HeapSt * st) {
	v8::HeapStatistics hs;
	if (isolate == NULL) {return;}

	isolate->GetHeapStatistics(&hs);

	st->total_heap_size = hs.total_heap_size();
	st->total_heap_size_executable = hs.total_heap_size_executable();
	st->total_physical_size = hs.total_physical_size();
	st->used_heap_size = hs.used_heap_size();
	st->heap_size_limit = hs.heap_size_limit();
}

bool IdleNotification(int ms) {
	if (isolate == NULL) {return false;}
	return v8::V8::IdleNotification(ms);
}

void LowMemoryNotification() {
	if (isolate == NULL) {return;}
	v8::V8::LowMemoryNotification();
}

<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
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 the author 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 <cctype>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

#if defined(_MSC_VER) && _MSC_VER < 1300
namespace std
{
	using ::isprint;
	using ::isdigit;
	using ::toupper;
	using ::isalnum;
}
#endif

namespace
{

	using namespace libtorrent;

	int decode_digit(char c)
	{
		if (std::isdigit(c)) return c - '0';
		return std::toupper(c) - 'A' + 10;
	}

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (id[0] != '-' || !std::isprint(id[1]) || !std::isprint(id[2])
			|| !std::isalnum(id[3]) || !std::isalnum(id[4])
			|| !std::isalnum(id[5]) || !std::isalnum(id[6])
			|| id[7] != '-')
			return boost::optional<fingerprint>();

		ret.id[0] = id[1];
		ret.id[1] = id[2];
		ret.major_version = decode_digit(id[3]);
		ret.minor_version = decode_digit(id[4]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = decode_digit(id[6]);

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (!std::isalnum(id[0]))
			return boost::optional<fingerprint>();

		if (std::equal(id.begin()+4, id.begin()+8, "----"))
		{
			if (!std::isalnum(id[1]) || !std::isalnum(id[2])
				|| !std::isalnum(id[3]))
				return boost::optional<fingerprint>();
			ret.major_version = decode_digit(id[1]);
			ret.minor_version = decode_digit(id[2]);
			ret.revision_version = decode_digit(id[3]);
		}
		else
		{
			if (id[8] != 0 || id[1] > 127 || id[2] > 127 || id[3] > 127)
				return boost::optional<fingerprint>();
			ret.major_version = id[1];
			ret.minor_version = id[2];
			ret.revision_version = id[3];
		}

		ret.id[0] = id[0];
		ret.id[1] = 0;

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		if (!std::isprint(id[0])
			|| !std::isalnum(id[1])
			|| id[2] != '-'
			|| !std::isalnum(id[3])
			|| id[4] != '-'
			|| !std::isalnum(id[5])
			|| !std::equal(id.begin() + 6, id.begin() + 8, "--"))
			return boost::optional<fingerprint>();

		fingerprint ret("..", 0, 0, 0, 0);

		ret.id[0] = id[0];
		ret.id[1] = 0;
		ret.major_version = decode_digit(id[1]);
		ret.minor_version = decode_digit(id[3]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	typedef std::pair<char const*, char const*> map_entry;

	// only support BitTorrentSpecification
	// must be ordered alphabetically
	map_entry name_map[] =
	{
		map_entry("A",  "ABC")
		, map_entry("AR", "Arctic Torrent")
		, map_entry("AZ", "Azureus")
		, map_entry("BB", "BitBuddy")
		, map_entry("BS", "BTSlave")
		, map_entry("BX", "BittorrentX")
		, map_entry("CT", "CTorrent")
		, map_entry("LT", "libtorrent")
		, map_entry("M",  "Mainline")
		, map_entry("MT", "Moonlight Torrent")
		, map_entry("S",  "Shadow")
		, map_entry("SN", "ShareNet")
		, map_entry("SS", "SwarmScope")
		, map_entry("T",  "BitTornado")
		, map_entry("TN", "Torrent.NET")
		, map_entry("TS", "TorrentStorm")
		, map_entry("U",  "UPnP")
		, map_entry("XT", "XanTorrent")
		, map_entry("ZT", "ZipTorrent")
	};

	bool compare_first_string(map_entry const& e, char const* str)
	{
		return e.first[0] < str[0]
			|| ((e.first[0] == str[0]) && (e.first[1] < str[1]));
	}

	std::string lookup(fingerprint const& f)
	{
		std::stringstream identity;

		const int size = sizeof(name_map)/sizeof(name_map[0]);
		map_entry* i =
			std::lower_bound(name_map, name_map + size
				, f.id, &compare_first_string);

		if (i < name_map + size && std::equal(f.id, f.id + 2, i->first))
			identity << i->second;
		else
			identity << std::string(f.id, f.id + 2);

		identity << " " << (int)f.major_version
			<< "." << (int)f.minor_version
			<< "." << (int)f.revision_version
			<< "." << (int)f.tag_version;

		return identity.str();
	}

	bool find_string(unsigned char const* id, char const* search)
	{
		return std::equal(search, search + std::strlen(search), id);
	}
}

namespace libtorrent
{

	std::string identify_client(const peer_id& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unknown";

		// ----------------------
		// non standard encodings
		// ----------------------

		if (find_string(PID, "Deadman Walking-")) return "Deadman";
		if (find_string(PID + 5, "Azureus")) return "Azureus 2.0.3.2";
		if (find_string(PID, "DansClient")) return "XanTorrent";
		if (find_string(PID + 4, "btfans")) return "SimpleBT";
		if (find_string(PID, "PRC.P---")) return "Bittorrent Plus! II";
		if (find_string(PID, "P87.P---")) return "Bittorrent Plus!";
		if (find_string(PID, "S587Plus")) return "Bittorrent Plus!";
		if (find_string(PID, "martini")) return "Martini Man";
		if (find_string(PID, "Plus---")) return "Bittorrent Plus";
		if (find_string(PID, "turbobt")) return "TurboBT";
		if (find_string(PID, "a00---0")) return "Swarmy";
		if (find_string(PID, "a02---0")) return "Swarmy";
		if (find_string(PID, "T00---0")) return "Teeweety";
		if (find_string(PID, "BTDWV-")) return "Deadman Walking";
		if (find_string(PID + 2, "BS")) return "BitSpirit";
		if (find_string(PID, "btuga")) return "BTugaXP";
		if (find_string(PID, "oernu")) return "BTugaXP";
		if (find_string(PID, "Mbrst")) return "Burst!";
		if (find_string(PID, "Plus")) return "Plus!";
		if (find_string(PID, "exbc")) return "BitComet";
		if (find_string(PID, "-G3")) return "G3 Torrent";
		if (find_string(PID, "XBT")) return "XBT";

		if (find_string(PID, "-BOW") && PID[7] == '-')
			return "Bits on Wheels " + std::string(PID + 4, PID + 7);

		if (find_string(PID, "eX"))
		{
			std::string user(PID + 2, PID + 14);
			return std::string("eXeem ('") + user.c_str() + "')";
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
			return "Experimental 3.2.1b2";

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Experimental 3.1";

      if (p.is_all_zeros()) return "Unknown";

		// look for azureus style id
		f = parse_az_style(p);
		if (f) return lookup(*f);

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return lookup(*f);

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return lookup(*f);

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Generic";

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<commit_msg>added MooPolice client identification<commit_after>/*

Copyright (c) 2003, Arvid Norberg
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 the author 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 <cctype>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

#if defined(_MSC_VER) && _MSC_VER < 1300
namespace std
{
	using ::isprint;
	using ::isdigit;
	using ::toupper;
	using ::isalnum;
}
#endif

namespace
{

	using namespace libtorrent;

	int decode_digit(char c)
	{
		if (std::isdigit(c)) return c - '0';
		return std::toupper(c) - 'A' + 10;
	}

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (id[0] != '-' || !std::isprint(id[1]) || !std::isprint(id[2])
			|| !std::isalnum(id[3]) || !std::isalnum(id[4])
			|| !std::isalnum(id[5]) || !std::isalnum(id[6])
			|| id[7] != '-')
			return boost::optional<fingerprint>();

		ret.id[0] = id[1];
		ret.id[1] = id[2];
		ret.major_version = decode_digit(id[3]);
		ret.minor_version = decode_digit(id[4]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = decode_digit(id[6]);

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (!std::isalnum(id[0]))
			return boost::optional<fingerprint>();

		if (std::equal(id.begin()+4, id.begin()+8, "----"))
		{
			if (!std::isalnum(id[1]) || !std::isalnum(id[2])
				|| !std::isalnum(id[3]))
				return boost::optional<fingerprint>();
			ret.major_version = decode_digit(id[1]);
			ret.minor_version = decode_digit(id[2]);
			ret.revision_version = decode_digit(id[3]);
		}
		else
		{
			if (id[8] != 0 || id[1] > 127 || id[2] > 127 || id[3] > 127)
				return boost::optional<fingerprint>();
			ret.major_version = id[1];
			ret.minor_version = id[2];
			ret.revision_version = id[3];
		}

		ret.id[0] = id[0];
		ret.id[1] = 0;

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		if (!std::isprint(id[0])
			|| !std::isalnum(id[1])
			|| id[2] != '-'
			|| !std::isalnum(id[3])
			|| id[4] != '-'
			|| !std::isalnum(id[5])
			|| !std::equal(id.begin() + 6, id.begin() + 8, "--"))
			return boost::optional<fingerprint>();

		fingerprint ret("..", 0, 0, 0, 0);

		ret.id[0] = id[0];
		ret.id[1] = 0;
		ret.major_version = decode_digit(id[1]);
		ret.minor_version = decode_digit(id[3]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	typedef std::pair<char const*, char const*> map_entry;

	// only support BitTorrentSpecification
	// must be ordered alphabetically
	map_entry name_map[] =
	{
		map_entry("A",  "ABC")
		, map_entry("AR", "Arctic Torrent")
		, map_entry("AZ", "Azureus")
		, map_entry("BB", "BitBuddy")
		, map_entry("BS", "BTSlave")
		, map_entry("BX", "BittorrentX")
		, map_entry("CT", "CTorrent")
		, map_entry("LT", "libtorrent")
		, map_entry("M",  "Mainline")
		. map_emtry("MP", "MooPolice")
		, map_entry("MT", "Moonlight Torrent")
		, map_entry("S",  "Shadow")
		, map_entry("SN", "ShareNet")
		, map_entry("SS", "SwarmScope")
		, map_entry("T",  "BitTornado")
		, map_entry("TN", "Torrent.NET")
		, map_entry("TS", "TorrentStorm")
		, map_entry("U",  "UPnP")
		, map_entry("XT", "XanTorrent")
		, map_entry("ZT", "ZipTorrent")
	};

	bool compare_first_string(map_entry const& e, char const* str)
	{
		return e.first[0] < str[0]
			|| ((e.first[0] == str[0]) && (e.first[1] < str[1]));
	}

	std::string lookup(fingerprint const& f)
	{
		std::stringstream identity;

		const int size = sizeof(name_map)/sizeof(name_map[0]);
		map_entry* i =
			std::lower_bound(name_map, name_map + size
				, f.id, &compare_first_string);

		if (i < name_map + size && std::equal(f.id, f.id + 2, i->first))
			identity << i->second;
		else
			identity << std::string(f.id, f.id + 2);

		identity << " " << (int)f.major_version
			<< "." << (int)f.minor_version
			<< "." << (int)f.revision_version
			<< "." << (int)f.tag_version;

		return identity.str();
	}

	bool find_string(unsigned char const* id, char const* search)
	{
		return std::equal(search, search + std::strlen(search), id);
	}
}

namespace libtorrent
{

	std::string identify_client(const peer_id& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unknown";

		// ----------------------
		// non standard encodings
		// ----------------------

		if (find_string(PID, "Deadman Walking-")) return "Deadman";
		if (find_string(PID + 5, "Azureus")) return "Azureus 2.0.3.2";
		if (find_string(PID, "DansClient")) return "XanTorrent";
		if (find_string(PID + 4, "btfans")) return "SimpleBT";
		if (find_string(PID, "PRC.P---")) return "Bittorrent Plus! II";
		if (find_string(PID, "P87.P---")) return "Bittorrent Plus!";
		if (find_string(PID, "S587Plus")) return "Bittorrent Plus!";
		if (find_string(PID, "martini")) return "Martini Man";
		if (find_string(PID, "Plus---")) return "Bittorrent Plus";
		if (find_string(PID, "turbobt")) return "TurboBT";
		if (find_string(PID, "a00---0")) return "Swarmy";
		if (find_string(PID, "a02---0")) return "Swarmy";
		if (find_string(PID, "T00---0")) return "Teeweety";
		if (find_string(PID, "BTDWV-")) return "Deadman Walking";
		if (find_string(PID + 2, "BS")) return "BitSpirit";
		if (find_string(PID, "btuga")) return "BTugaXP";
		if (find_string(PID, "oernu")) return "BTugaXP";
		if (find_string(PID, "Mbrst")) return "Burst!";
		if (find_string(PID, "Plus")) return "Plus!";
		if (find_string(PID, "exbc")) return "BitComet";
		if (find_string(PID, "-G3")) return "G3 Torrent";
		if (find_string(PID, "XBT")) return "XBT";

		if (find_string(PID, "-BOW") && PID[7] == '-')
			return "Bits on Wheels " + std::string(PID + 4, PID + 7);

		if (find_string(PID, "eX"))
		{
			std::string user(PID + 2, PID + 14);
			return std::string("eXeem ('") + user.c_str() + "')";
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
			return "Experimental 3.2.1b2";

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Experimental 3.1";

      if (p.is_all_zeros()) return "Unknown";

		// look for azureus style id
		f = parse_az_style(p);
		if (f) return lookup(*f);

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return lookup(*f);

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return lookup(*f);

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Generic";

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
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 the author 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 <cctype>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

#if defined(_MSC_VER) && _MSC_VER < 1300
namespace std
{
	using ::isprint;
	using ::isdigit;
	using ::toupper;
	using ::isalnum;
}
#endif

namespace
{

	using namespace libtorrent;

	int decode_digit(char c)
	{
		if (std::isdigit(c)) return c - '0';
		return std::toupper(c) - 'A' + 10;
	}

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (id[0] != '-' || !std::isprint(id[1]) || !std::isprint(id[2])
			|| !std::isalnum(id[3]) || !std::isalnum(id[4])
			|| !std::isalnum(id[5]) || !std::isalnum(id[6])
			|| id[7] != '-')
			return boost::optional<fingerprint>();

		ret.id[0] = id[1];
		ret.id[1] = id[2];
		ret.major_version = decode_digit(id[3]);
		ret.minor_version = decode_digit(id[4]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = decode_digit(id[6]);

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (!std::isalnum(id[0]))
			return boost::optional<fingerprint>();

		if (std::equal(id.begin()+4, id.begin()+8, "----"))
		{
			if (!std::isalnum(id[1]) || !std::isalnum(id[2])
				|| !std::isalnum(id[3]))
				return boost::optional<fingerprint>();
			ret.major_version = decode_digit(id[1]);
			ret.minor_version = decode_digit(id[2]);
			ret.revision_version = decode_digit(id[3]);
		}
		else
		{
			if (id[8] != 0 || id[1] > 127 || id[2] > 127 || id[3] > 127)
				return boost::optional<fingerprint>();
			ret.major_version = id[1];
			ret.minor_version = id[2];
			ret.revision_version = id[3];
		}

		ret.id[0] = id[0];
		ret.id[1] = 0;

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		if (!std::isprint(id[0])
			|| !std::isalnum(id[1])
			|| id[2] != '-'
			|| !std::isalnum(id[3])
			|| id[4] != '-'
			|| !std::isalnum(id[5])
			|| !std::equal(id.begin() + 6, id.begin() + 8, "--"))
			return boost::optional<fingerprint>();

		fingerprint ret("..", 0, 0, 0, 0);

		ret.id[0] = id[0];
		ret.id[1] = 0;
		ret.major_version = decode_digit(id[1]);
		ret.minor_version = decode_digit(id[3]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	typedef std::pair<char const*, char const*> map_entry;

	// only support BitTorrentSpecification
	// must be ordered alphabetically
	map_entry name_map[] =
	{
		map_entry("A",  "ABC")
		, map_entry("AR", "Arctic Torrent")
		, map_entry("AZ", "Azureus")
		, map_entry("BB", "BitBuddy")
		, map_entry("BS", "BTSlave")
		, map_entry("BX", "BittorrentX")
		, map_entry("CT", "CTorrent")
		, map_entry("LT", "libtorrent")
		, map_entry("M",  "Mainline")
		. map_emtry("MP", "MooPolice")
		, map_entry("MT", "Moonlight Torrent")
		, map_entry("S",  "Shadow")
		, map_entry("SN", "ShareNet")
		, map_entry("SS", "SwarmScope")
		, map_entry("T",  "BitTornado")
		, map_entry("TN", "Torrent.NET")
		, map_entry("TS", "TorrentStorm")
		, map_entry("U",  "UPnP")
		, map_entry("XT", "XanTorrent")
		, map_entry("ZT", "ZipTorrent")
	};

	bool compare_first_string(map_entry const& e, char const* str)
	{
		return e.first[0] < str[0]
			|| ((e.first[0] == str[0]) && (e.first[1] < str[1]));
	}

	std::string lookup(fingerprint const& f)
	{
		std::stringstream identity;

		const int size = sizeof(name_map)/sizeof(name_map[0]);
		map_entry* i =
			std::lower_bound(name_map, name_map + size
				, f.id, &compare_first_string);

		if (i < name_map + size && std::equal(f.id, f.id + 2, i->first))
			identity << i->second;
		else
			identity << std::string(f.id, f.id + 2);

		identity << " " << (int)f.major_version
			<< "." << (int)f.minor_version
			<< "." << (int)f.revision_version
			<< "." << (int)f.tag_version;

		return identity.str();
	}

	bool find_string(unsigned char const* id, char const* search)
	{
		return std::equal(search, search + std::strlen(search), id);
	}
}

namespace libtorrent
{

	std::string identify_client(const peer_id& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unknown";

		// ----------------------
		// non standard encodings
		// ----------------------

		if (find_string(PID, "Deadman Walking-")) return "Deadman";
		if (find_string(PID + 5, "Azureus")) return "Azureus 2.0.3.2";
		if (find_string(PID, "DansClient")) return "XanTorrent";
		if (find_string(PID + 4, "btfans")) return "SimpleBT";
		if (find_string(PID, "PRC.P---")) return "Bittorrent Plus! II";
		if (find_string(PID, "P87.P---")) return "Bittorrent Plus!";
		if (find_string(PID, "S587Plus")) return "Bittorrent Plus!";
		if (find_string(PID, "martini")) return "Martini Man";
		if (find_string(PID, "Plus---")) return "Bittorrent Plus";
		if (find_string(PID, "turbobt")) return "TurboBT";
		if (find_string(PID, "a00---0")) return "Swarmy";
		if (find_string(PID, "a02---0")) return "Swarmy";
		if (find_string(PID, "T00---0")) return "Teeweety";
		if (find_string(PID, "BTDWV-")) return "Deadman Walking";
		if (find_string(PID + 2, "BS")) return "BitSpirit";
		if (find_string(PID, "btuga")) return "BTugaXP";
		if (find_string(PID, "oernu")) return "BTugaXP";
		if (find_string(PID, "Mbrst")) return "Burst!";
		if (find_string(PID, "Plus")) return "Plus!";
		if (find_string(PID, "exbc")) return "BitComet";
		if (find_string(PID, "-G3")) return "G3 Torrent";
		if (find_string(PID, "XBT")) return "XBT";

		if (find_string(PID, "-BOW") && PID[7] == '-')
			return "Bits on Wheels " + std::string(PID + 4, PID + 7);

		if (find_string(PID, "eX"))
		{
			std::string user(PID + 2, PID + 14);
			return std::string("eXeem ('") + user.c_str() + "')";
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
			return "Experimental 3.2.1b2";

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Experimental 3.1";

      if (p.is_all_zeros()) return "Unknown";

		// look for azureus style id
		f = parse_az_style(p);
		if (f) return lookup(*f);

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return lookup(*f);

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return lookup(*f);

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Generic";

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<commit_msg>*** empty log message ***<commit_after>/*

Copyright (c) 2003, Arvid Norberg
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 the author 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 <cctype>
#include <algorithm>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

#if defined(_MSC_VER) && _MSC_VER < 1300
namespace std
{
	using ::isprint;
	using ::isdigit;
	using ::toupper;
	using ::isalnum;
}
#endif

namespace
{

	using namespace libtorrent;

	int decode_digit(char c)
	{
		if (std::isdigit(c)) return c - '0';
		return std::toupper(c) - 'A' + 10;
	}

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (id[0] != '-' || !std::isprint(id[1]) || !std::isprint(id[2])
			|| !std::isalnum(id[3]) || !std::isalnum(id[4])
			|| !std::isalnum(id[5]) || !std::isalnum(id[6])
			|| id[7] != '-')
			return boost::optional<fingerprint>();

		ret.id[0] = id[1];
		ret.id[1] = id[2];
		ret.major_version = decode_digit(id[3]);
		ret.minor_version = decode_digit(id[4]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = decode_digit(id[6]);

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);

		if (!std::isalnum(id[0]))
			return boost::optional<fingerprint>();

		if (std::equal(id.begin()+4, id.begin()+8, "----"))
		{
			if (!std::isalnum(id[1]) || !std::isalnum(id[2])
				|| !std::isalnum(id[3]))
				return boost::optional<fingerprint>();
			ret.major_version = decode_digit(id[1]);
			ret.minor_version = decode_digit(id[2]);
			ret.revision_version = decode_digit(id[3]);
		}
		else
		{
			if (id[8] != 0 || id[1] > 127 || id[2] > 127 || id[3] > 127)
				return boost::optional<fingerprint>();
			ret.major_version = id[1];
			ret.minor_version = id[2];
			ret.revision_version = id[3];
		}

		ret.id[0] = id[0];
		ret.id[1] = 0;

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		if (!std::isprint(id[0])
			|| !std::isalnum(id[1])
			|| id[2] != '-'
			|| !std::isalnum(id[3])
			|| id[4] != '-'
			|| !std::isalnum(id[5])
			|| !std::equal(id.begin() + 6, id.begin() + 8, "--"))
			return boost::optional<fingerprint>();

		fingerprint ret("..", 0, 0, 0, 0);

		ret.id[0] = id[0];
		ret.id[1] = 0;
		ret.major_version = decode_digit(id[1]);
		ret.minor_version = decode_digit(id[3]);
		ret.revision_version = decode_digit(id[5]);
		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	typedef std::pair<char const*, char const*> map_entry;

	// only support BitTorrentSpecification
	// must be ordered alphabetically
	map_entry name_map[] =
	{
		map_entry("A",  "ABC")
		, map_entry("AR", "Arctic Torrent")
		, map_entry("AZ", "Azureus")
		, map_entry("BB", "BitBuddy")
		, map_entry("BS", "BTSlave")
		, map_entry("BX", "BittorrentX")
		, map_entry("CT", "CTorrent")
		, map_entry("LT", "libtorrent")
		, map_entry("M",  "Mainline")
		, map_entry("MP", "MooPolice")
		, map_entry("MT", "Moonlight Torrent")
		, map_entry("S",  "Shadow")
		, map_entry("SN", "ShareNet")
		, map_entry("SS", "SwarmScope")
		, map_entry("T",  "BitTornado")
		, map_entry("TN", "Torrent.NET")
		, map_entry("TS", "TorrentStorm")
		, map_entry("U",  "UPnP")
		, map_entry("XT", "XanTorrent")
		, map_entry("ZT", "ZipTorrent")
	};

	bool compare_first_string(map_entry const& e, char const* str)
	{
		return e.first[0] < str[0]
			|| ((e.first[0] == str[0]) && (e.first[1] < str[1]));
	}

	std::string lookup(fingerprint const& f)
	{
		std::stringstream identity;

		const int size = sizeof(name_map)/sizeof(name_map[0]);
		map_entry* i =
			std::lower_bound(name_map, name_map + size
				, f.id, &compare_first_string);

#ifndef NDEBUG
		for (int i = 1; i < size; ++i)
		{
			assert(compare_first_string(name_map[i-1]
				, name_map[i].first));
		}
#endif

		if (i < name_map + size && std::equal(f.id, f.id + 2, i->first))
			identity << i->second;
		else
			identity << std::string(f.id, f.id + 2);

		identity << " " << (int)f.major_version
			<< "." << (int)f.minor_version
			<< "." << (int)f.revision_version
			<< "." << (int)f.tag_version;

		return identity.str();
	}

	bool find_string(unsigned char const* id, char const* search)
	{
		return std::equal(search, search + std::strlen(search), id);
	}
}

namespace libtorrent
{

	std::string identify_client(const peer_id& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unknown";

		// ----------------------
		// non standard encodings
		// ----------------------

		if (find_string(PID, "Deadman Walking-")) return "Deadman";
		if (find_string(PID + 5, "Azureus")) return "Azureus 2.0.3.2";
		if (find_string(PID, "DansClient")) return "XanTorrent";
		if (find_string(PID + 4, "btfans")) return "SimpleBT";
		if (find_string(PID, "PRC.P---")) return "Bittorrent Plus! II";
		if (find_string(PID, "P87.P---")) return "Bittorrent Plus!";
		if (find_string(PID, "S587Plus")) return "Bittorrent Plus!";
		if (find_string(PID, "martini")) return "Martini Man";
		if (find_string(PID, "Plus---")) return "Bittorrent Plus";
		if (find_string(PID, "turbobt")) return "TurboBT";
		if (find_string(PID, "a00---0")) return "Swarmy";
		if (find_string(PID, "a02---0")) return "Swarmy";
		if (find_string(PID, "T00---0")) return "Teeweety";
		if (find_string(PID, "BTDWV-")) return "Deadman Walking";
		if (find_string(PID + 2, "BS")) return "BitSpirit";
		if (find_string(PID, "btuga")) return "BTugaXP";
		if (find_string(PID, "oernu")) return "BTugaXP";
		if (find_string(PID, "Mbrst")) return "Burst!";
		if (find_string(PID, "Plus")) return "Plus!";
		if (find_string(PID, "exbc")) return "BitComet";
		if (find_string(PID, "-G3")) return "G3 Torrent";
		if (find_string(PID, "XBT")) return "XBT";

		if (find_string(PID, "-BOW") && PID[7] == '-')
			return "Bits on Wheels " + std::string(PID + 4, PID + 7);

		if (find_string(PID, "eX"))
		{
			std::string user(PID + 2, PID + 14);
			return std::string("eXeem ('") + user.c_str() + "')";
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
			return "Experimental 3.2.1b2";

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Experimental 3.1";

		// look for azureus style id
		f = parse_az_style(p);
		if (f) return lookup(*f);

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f) return lookup(*f);

		// look for mainline style id
		f = parse_mainline_style(p);
		if (f) return lookup(*f);

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
			return "Generic";

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
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 the author 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 <cctype>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

#if defined(_MSC_VER) && _MSC_VER < 1300
namespace std
{
	using ::isprint;
	using ::isdigit;
}
#endif

namespace
{

	using namespace libtorrent;

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);
		peer_id::const_iterator i = id.begin();

		if (*i != '-') return boost::optional<fingerprint>();
		++i;

		for (int j = 0; j < 2; ++j)
		{
			if (!std::isprint(*i)) return boost::optional<fingerprint>();
			ret.id[j] = *i;
			++i;
		}

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.major_version = *i - '0';
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.minor_version = *i - '0';
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.revision_version = *i - '0';
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.tag_version = *i - '0';
		++i;

		if (*i != '-') return boost::optional<fingerprint>();

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);
		peer_id::const_iterator i = id.begin();

		if (!std::isprint(*i)) return boost::optional<fingerprint>();
		ret.id[0] = *i;
		ret.id[1] = 0;
		++i;

		if (std::equal(id.begin()+4, id.begin()+8, "----"))
		{
			if (!std::isdigit(*i)) return boost::optional<fingerprint>();
			ret.major_version = *i - '0';
			++i;

			if (!std::isdigit(*i)) return boost::optional<fingerprint>();
			ret.minor_version = *i - '0';
			++i;

			if (!std::isdigit(*i)) return boost::optional<fingerprint>();
			ret.revision_version = *i - '0';
		}
		else if (id[8] == 0)
		{
			if (*i > 127) return boost::optional<fingerprint>();
			ret.major_version = *i;
			++i;

			if (*i > 127) return boost::optional<fingerprint>();
			ret.minor_version = *i;
			++i;

			if (*i > 127) return boost::optional<fingerprint>();
			ret.revision_version = *i;
		}
		else
			return boost::optional<fingerprint>();

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);
		peer_id::const_iterator i = id.begin();

		if (!std::isprint(*i)) return boost::optional<fingerprint>();
		ret.id[0] = *i;
		ret.id[1] = 0;
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.major_version = *i - '0';
		++i;

		if (*i != '-') return boost::optional<fingerprint>();
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.minor_version = *i - '0';
		++i;

		if (*i != '-') return boost::optional<fingerprint>();
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.revision_version = *i - '0';
		++i;

		if (!std::equal(i, i+1, "--")) return boost::optional<fingerprint>();

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

} // namespace unnamed

namespace libtorrent
{

	std::string identify_client(const peer_id& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unkown";

		// look for azureus style id
		f = parse_az_style(p);
		if (f)
		{
			std::stringstream identity;

			// azureus
			if (std::equal(f->id, f->id+2, "AZ"))
				identity << "Azureus ";

			// BittorrentX
			else if (std::equal(f->id, f->id+2, "BX"))
				identity << "BittorrentX ";

			// libtorrent
			else if (std::equal(f->id, f->id+2, "LT"))
				identity << "libtorrent ";

			// Moonlight Torrent
			else if (std::equal(f->id, f->id+2, "MT"))
				identity << "Moonlight Torrent ";

			// Torrent Storm
			else if (std::equal(f->id, f->id+2, "TS"))
				identity << "TorrentStorm ";

			// SwarmScope
			else if (std::equal(f->id, f->id+2, "SS"))
				identity << "SwarmScope ";

			// XanTorrent
			else if (std::equal(f->id, f->id+2, "XT"))
				identity << "XanTorrent ";

			// unknown client
			else
				identity << std::string(f->id, f->id+2) << " ";

			identity << (int)f->major_version
				<< "." << (int)f->minor_version
				<< "." << (int)f->revision_version
				<< "." << (int)f->tag_version;

			return identity.str();
		}

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f)
		{
			std::stringstream identity;

			// Shadow
			if (std::equal(f->id, f->id+1, "S"))
				identity << "Shadow ";

			// ABC
			if (std::equal(f->id, f->id+1, "A"))
				identity << "ABC ";

			// UPnP
			else if (std::equal(f->id, f->id+1, "U"))
				identity << "UPnP ";

			// BitTornado
			else if (std::equal(f->id, f->id+1, "T"))
				identity << "BitTornado ";

			// unknown client
			else
				identity << std::string(f->id, f->id+1) << " ";

			identity << (int)f->major_version
				<< "." << (int)f->minor_version
				<< "." << (int)f->revision_version;

			return identity.str();
		}

		f = parse_mainline_style(p);
		if (f)
		{
			std::stringstream identity;

			// Mainline
			if (std::equal(f->id, f->id+1, "M"))
				identity << "Mainline ";

			// unknown client
			else
				identity << std::string(f->id, f->id+1) << " ";

			identity << (int)f->major_version
				<< "." << (int)f->minor_version
				<< "." << (int)f->revision_version;

			return identity.str();
		}

		// ----------------------
		// non standard encodings
		// ----------------------

		if (std::equal(PID, PID + 12, "-G3g3rmz    "))
		{
			return "G3 Torrent";
		}

		if (std::equal(PID, PID + 4, "exbc"))
		{
			std::stringstream s;
			s << "BitComet " << (int)PID[4] << "." << (int)PID[5]/10 << (int)PID[5]%10;
			return s.str();
		}

		if (std::equal(PID + 5, PID + 5 + 8, "Azureus"))
		{
			return "Azureus 2.0.3.2";
		}

		if (std::equal(PID, PID + 11, "DansClient"))
		{
			return "XanTorrent";
		}

		if (std::equal(PID, PID + 7, "Plus---"))
		{
			return "Bittorrent Plus";
		}

		if (std::equal(PID, PID + 16, "Deadman Walking-"))
		{
			return "Deadman";
		}

		if (std::equal(PID, PID + 7, "btuga"))
		{
			return "BTugaXP";
		}

		if (std::equal(PID, PID + 7, "btfans"))
		{
			return "SimpleBT";
		}

		if (std::equal(PID, PID + 7, "turbobt"))
		{
			std::stringstream s;
			s << "TurboBT " << PID[8] << "." << PID[10] << "." << PID[12];
			return s.str();
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
		{
			return "Experimental 3.2.1b2";
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
		{
			return "Experimental 3.1";
		}

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
		{
			return "Generic";
		}

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<commit_msg>*** empty log message ***<commit_after>/*

Copyright (c) 2003, Arvid Norberg
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 the author 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 <cctype>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/optional.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/identify_client.hpp"
#include "libtorrent/fingerprint.hpp"

#if defined(_MSC_VER) && _MSC_VER < 1300
namespace std
{
	using ::isprint;
	using ::isdigit;
}
#endif

namespace
{

	using namespace libtorrent;

	// takes a peer id and returns a valid boost::optional
	// object if the peer id matched the azureus style encoding
	// the returned fingerprint contains information about the
	// client's id
	boost::optional<fingerprint> parse_az_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);
		peer_id::const_iterator i = id.begin();

		if (*i != '-') return boost::optional<fingerprint>();
		++i;

		for (int j = 0; j < 2; ++j)
		{
			if (!std::isprint(*i)) return boost::optional<fingerprint>();
			ret.id[j] = *i;
			++i;
		}

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.major_version = *i - '0';
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.minor_version = *i - '0';
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.revision_version = *i - '0';
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.tag_version = *i - '0';
		++i;

		if (*i != '-') return boost::optional<fingerprint>();

		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a shadow-style
	// identification
	boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);
		peer_id::const_iterator i = id.begin();

		if (!std::isprint(*i)) return boost::optional<fingerprint>();
		ret.id[0] = *i;
		ret.id[1] = 0;
		++i;

		if (std::equal(id.begin()+4, id.begin()+8, "----"))
		{
			if (!std::isdigit(*i)) return boost::optional<fingerprint>();
			ret.major_version = *i - '0';
			++i;

			if (!std::isdigit(*i)) return boost::optional<fingerprint>();
			ret.minor_version = *i - '0';
			++i;

			if (!std::isdigit(*i)) return boost::optional<fingerprint>();
			ret.revision_version = *i - '0';
		}
		else if (id[8] == 0)
		{
			if (*i > 127) return boost::optional<fingerprint>();
			ret.major_version = *i;
			++i;

			if (*i > 127) return boost::optional<fingerprint>();
			ret.minor_version = *i;
			++i;

			if (*i > 127) return boost::optional<fingerprint>();
			ret.revision_version = *i;
		}
		else
			return boost::optional<fingerprint>();

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

	// checks if a peer id can possibly contain a mainline-style
	// identification
	boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
	{
		fingerprint ret("..", 0, 0, 0, 0);
		peer_id::const_iterator i = id.begin();

		if (!std::isprint(*i)) return boost::optional<fingerprint>();
		ret.id[0] = *i;
		ret.id[1] = 0;
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.major_version = *i - '0';
		++i;

		if (*i != '-') return boost::optional<fingerprint>();
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.minor_version = *i - '0';
		++i;

		if (*i != '-') return boost::optional<fingerprint>();
		++i;

		if (!std::isdigit(*i)) return boost::optional<fingerprint>();
		ret.revision_version = *i - '0';
		++i;

		if (!std::equal(i, i+1, "--")) return boost::optional<fingerprint>();

		ret.tag_version = 0;
		return boost::optional<fingerprint>(ret);
	}

} // namespace unnamed

namespace libtorrent
{

	std::string identify_client(const peer_id& p)
	{
		peer_id::const_iterator PID = p.begin();
		boost::optional<fingerprint> f;

		if (p.is_all_zeros()) return "Unkown";

		// look for azureus style id
		f = parse_az_style(p);
		if (f)
		{
			std::stringstream identity;

			// azureus
			if (std::equal(f->id, f->id+2, "AZ"))
				identity << "Azureus ";

			// BittorrentX
			else if (std::equal(f->id, f->id+2, "BX"))
				identity << "BittorrentX ";

			// libtorrent
			else if (std::equal(f->id, f->id+2, "LT"))
				identity << "libtorrent ";

			// Moonlight Torrent
			else if (std::equal(f->id, f->id+2, "MT"))
				identity << "Moonlight Torrent ";

			// Torrent Storm
			else if (std::equal(f->id, f->id+2, "TS"))
				identity << "TorrentStorm ";

			// SwarmScope
			else if (std::equal(f->id, f->id+2, "SS"))
				identity << "SwarmScope ";

			// XanTorrent
			else if (std::equal(f->id, f->id+2, "XT"))
				identity << "XanTorrent ";

			// unknown client
			else
				identity << std::string(f->id, f->id+2) << " ";

			identity << (int)f->major_version
				<< "." << (int)f->minor_version
				<< "." << (int)f->revision_version
				<< "." << (int)f->tag_version;

			return identity.str();
		}

		// look for shadow style id
		f = parse_shadow_style(p);
		if (f)
		{
			std::stringstream identity;

			// Shadow
			if (std::equal(f->id, f->id+1, "S"))
				identity << "Shadow ";

			// ABC
			else if (std::equal(f->id, f->id+1, "A"))
				identity << "ABC ";

			// UPnP
			else if (std::equal(f->id, f->id+1, "U"))
				identity << "UPnP ";

			// BitTornado
			else if (std::equal(f->id, f->id+1, "T"))
				identity << "BitTornado ";

			// unknown client
			else
				identity << std::string(f->id, f->id+1) << " ";

			identity << (int)f->major_version
				<< "." << (int)f->minor_version
				<< "." << (int)f->revision_version;

			return identity.str();
		}

		f = parse_mainline_style(p);
		if (f)
		{
			std::stringstream identity;

			// Mainline
			if (std::equal(f->id, f->id+1, "M"))
				identity << "Mainline ";

			// unknown client
			else
				identity << std::string(f->id, f->id+1) << " ";

			identity << (int)f->major_version
				<< "." << (int)f->minor_version
				<< "." << (int)f->revision_version;

			return identity.str();
		}

		// ----------------------
		// non standard encodings
		// ----------------------

		if (std::equal(PID, PID + 12, "-G3g3rmz    "))
		{
			return "G3 Torrent";
		}

		if (std::equal(PID, PID + 4, "exbc"))
		{
			std::stringstream s;
			s << "BitComet " << (int)PID[4] << "." << (int)PID[5]/10 << (int)PID[5]%10;
			return s.str();
		}

		if (std::equal(PID + 5, PID + 5 + 8, "Azureus"))
		{
			return "Azureus 2.0.3.2";
		}

		if (std::equal(PID, PID + 11, "DansClient"))
		{
			return "XanTorrent";
		}

		if (std::equal(PID, PID + 7, "Plus---"))
		{
			return "Bittorrent Plus";
		}

		if (std::equal(PID, PID + 16, "Deadman Walking-"))
		{
			return "Deadman";
		}

		if (std::equal(PID, PID + 7, "btuga"))
		{
			return "BTugaXP";
		}

		if (std::equal(PID, PID + 7, "btfans"))
		{
			return "SimpleBT";
		}

		if (std::equal(PID, PID + 7, "turbobt"))
		{
			std::stringstream s;
			s << "TurboBT " << PID[8] << "." << PID[10] << "." << PID[12];
			return s.str();
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
		{
			return "Experimental 3.2.1b2";
		}

		if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
		{
			return "Experimental 3.1";
		}

		if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
		{
			return "Generic";
		}

		std::string unknown("Unknown [");
		for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
		{
			unknown += std::isprint(*i)?*i:'.';
		}
		unknown += "]";
		return unknown;
	}

}
<|endoftext|>