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

#include "MediaStream.h"

using namespace v8;
using namespace WebRTC;

Persistent<Function> MediaStream::constructor;

void MediaStream::Init() {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, MediaStream::New);
  tpl->SetClassName(String::NewFromUtf8(isolate, "MediaStream"));

  tpl->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "addTrack"),
                                FunctionTemplate::New(isolate, MediaStream::AddTrack));

  tpl->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "removeTrack"),
                                FunctionTemplate::New(isolate, MediaStream::RemoveTrack));

  tpl->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "clone"),
                                FunctionTemplate::New(isolate, MediaStream::Clone));

  tpl->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getAudioTracks"),
                                FunctionTemplate::New(isolate, MediaStream::GetAudioTracks));

  tpl->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getTrackById"),
                                FunctionTemplate::New(isolate, MediaStream::GetTrackById));

  tpl->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getVideoTracks"),
                                FunctionTemplate::New(isolate, MediaStream::GetVideoTracks));

  tpl->InstanceTemplate()->SetAccessor(String::NewFromUtf8(isolate, "ended"),
                                       MediaStream::GetEnded,
                                       MediaStream::ReadOnly);

  tpl->InstanceTemplate()->SetAccessor(String::NewFromUtf8(isolate, "id"),
                                       MediaStream::GetId,
                                       MediaStream::ReadOnly);

  tpl->InstanceTemplate()->SetAccessor(String::NewFromUtf8(isolate, "onaddtrack"),
                                       MediaStream::GetOnAddTrack,
                                       MediaStream::SetOnAddTrack);

  tpl->InstanceTemplate()->SetAccessor(String::NewFromUtf8(isolate, "onremovetrack"),
                                       MediaStream::GetOnRemoveTrack,
                                       MediaStream::SetOnRemoveTrack);

  tpl->InstanceTemplate()->SetAccessor(String::NewFromUtf8(isolate, "onended"),
                                       MediaStream::GetOnEnded,
                                       MediaStream::SetOnEnded);

  constructor.Reset(isolate, tpl->GetFunction());
}

Local<Value> MediaStream::New(Isolate *isolate, rtc::scoped_refptr<webrtc::MediaStreamInterface> mediaStream) {
  EscapableHandleScope scope(isolate);

  Local<Value> argv[1];
  Local<Function> instance = Local<Function>::New(isolate, MediaStream::constructor);

  if (instance.IsEmpty() || !mediaStream.get()) {
    Local<Value> empty = Null(isolate);
    return scope.Escape(empty);
  }

  Local<Object> ret = instance->NewInstance(0, argv);
  MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, ret);

  self->_stream = mediaStream;

  // TODO(): Implement This

  return scope.Escape(ret);
}

MediaStream::MediaStream() {

}

MediaStream::~MediaStream() {

}

void MediaStream::New(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();
  HandleScope scope(isolate);

  if (args.IsConstructCall()) {
    MediaStream* mediaStream = new MediaStream();
    mediaStream->Wrap(isolate, args.This());
    return args.GetReturnValue().Set(args.This());
  }

  isolate->ThrowException(Exception::Error(String::NewFromUtf8(isolate, "Internal Error")));
}

void MediaStream::AddTrack(const FunctionCallbackInfo<Value>& args) {
  //Isolate *isolate = args.GetIsolate();
  //MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, args.This());

  // TODO(): Implement This
}

void MediaStream::Clone(const FunctionCallbackInfo<Value>& args) {
  //Isolate *isolate = args.GetIsolate();
  //MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, args.This());

  // TODO(): Implement This
}

void MediaStream::GetTrackById(const FunctionCallbackInfo<Value>& args) {
  //Isolate *isolate = args.GetIsolate();
  //MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, args.This());

  // TODO(): Implement This
}

void MediaStream::GetAudioTracks(const FunctionCallbackInfo<Value>& args) {
  //Isolate *isolate = args.GetIsolate();
  //MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, args.This());

  // TODO(): Implement This
}

void MediaStream::GetVideoTracks(const FunctionCallbackInfo<Value>& args) {
  //Isolate *isolate = args.GetIsolate();
  //MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, args.This());

  // TODO(): Implement This
}

void MediaStream::RemoveTrack(const FunctionCallbackInfo<Value>& args) {
  //Isolate *isolate = args.GetIsolate();
  //MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, args.This());

  // TODO(): Implement This
}

void MediaStream::GetEnded(Local<String> property,
                           const PropertyCallbackInfo<Value> &info)
{
  //Isolate *isolate = args.GetIsolate();
  //MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, args.This());

  // TODO(): Implement This
}
void MediaStream::GetId(Local<String> property,
                        const PropertyCallbackInfo<Value> &info)
{
  //Isolate *isolate = args.GetIsolate();
  //MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, args.This());

  // TODO(): Implement This
}

void MediaStream::GetOnAddTrack(Local<String> property,
                                const PropertyCallbackInfo<Value> &info)
{
  Isolate *isolate = info.GetIsolate();
  MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, info.Holder());
  info.GetReturnValue().Set(Local<Function>::New(isolate, self->_onaddtrack));
}

void MediaStream::GetOnRemoveTrack(Local<String> property,
                                   const PropertyCallbackInfo<Value> &info)
{
  Isolate *isolate = info.GetIsolate();
  MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, info.Holder());
  info.GetReturnValue().Set(Local<Function>::New(isolate, self->_onremovetrack));
}

void MediaStream::GetOnEnded(Local<String> property,
                             const PropertyCallbackInfo<Value> &info)
{
  Isolate *isolate = info.GetIsolate();
  MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, info.Holder());
  info.GetReturnValue().Set(Local<Function>::New(isolate, self->_onended));
}

void MediaStream::ReadOnly(Local<String> property,
                           Local<Value> value,
                           const PropertyCallbackInfo<void> &info)
{

}

void MediaStream::SetOnAddTrack(Local<String> property,
                                Local<Value> value,
                                const PropertyCallbackInfo<void> &info)
{
  Isolate *isolate = info.GetIsolate();
  MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, info.Holder());

  if (!value.IsEmpty() && value->IsFunction()) {
    self->_onaddtrack.Reset(isolate, Local<Function>::Cast(value));
  }
  else {
    self->_onaddtrack.Reset();
  }
}

void MediaStream::SetOnRemoveTrack(Local<String> property,
                                   Local<Value> value,
                                   const PropertyCallbackInfo<void> &info)
{
  Isolate *isolate = info.GetIsolate();
  MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, info.Holder());

  if (!value.IsEmpty() && value->IsFunction()) {
    self->_onremovetrack.Reset(isolate, Local<Function>::Cast(value));
  }
  else {
    self->_onremovetrack.Reset();
  }
}

void MediaStream::SetOnEnded(Local<String> property,
                             Local<Value> value,
                             const PropertyCallbackInfo<void> &info)
{
  Isolate *isolate = info.GetIsolate();
  MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, info.Holder());

  if (!value.IsEmpty() && value->IsFunction()) {
    self->_onended.Reset(isolate, Local<Function>::Cast(value));
  }
  else {
    self->_onended.Reset();
  }
}

void MediaStream::On(Event *event) {

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

#include "MediaStream.h"

using namespace v8;
using namespace WebRTC;

Persistent<Function> MediaStream::constructor;

void MediaStream::Init() {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, MediaStream::New);
  tpl->SetClassName(String::NewFromUtf8(isolate, "MediaStream"));

  tpl->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "addTrack"),
                                FunctionTemplate::New(isolate, MediaStream::AddTrack));

  tpl->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "removeTrack"),
                                FunctionTemplate::New(isolate, MediaStream::RemoveTrack));

  tpl->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "clone"),
                                FunctionTemplate::New(isolate, MediaStream::Clone));

  tpl->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getAudioTracks"),
                                FunctionTemplate::New(isolate, MediaStream::GetAudioTracks));

  tpl->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getTrackById"),
                                FunctionTemplate::New(isolate, MediaStream::GetTrackById));

  tpl->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getVideoTracks"),
                                FunctionTemplate::New(isolate, MediaStream::GetVideoTracks));

  tpl->InstanceTemplate()->SetAccessor(String::NewFromUtf8(isolate, "ended"),
                                       MediaStream::GetEnded,
                                       MediaStream::ReadOnly);

  tpl->InstanceTemplate()->SetAccessor(String::NewFromUtf8(isolate, "id"),
                                       MediaStream::GetId,
                                       MediaStream::ReadOnly);

  tpl->InstanceTemplate()->SetAccessor(String::NewFromUtf8(isolate, "onaddtrack"),
                                       MediaStream::GetOnAddTrack,
                                       MediaStream::SetOnAddTrack);

  tpl->InstanceTemplate()->SetAccessor(String::NewFromUtf8(isolate, "onremovetrack"),
                                       MediaStream::GetOnRemoveTrack,
                                       MediaStream::SetOnRemoveTrack);

  tpl->InstanceTemplate()->SetAccessor(String::NewFromUtf8(isolate, "onended"),
                                       MediaStream::GetOnEnded,
                                       MediaStream::SetOnEnded);

  constructor.Reset(isolate, tpl->GetFunction());
}

Local<Value> MediaStream::New(Isolate *isolate, rtc::scoped_refptr<webrtc::MediaStreamInterface> mediaStream) {
  EscapableHandleScope scope(isolate);

  Local<Value> argv[1];
  Local<Function> instance = Local<Function>::New(isolate, MediaStream::constructor);

  if (instance.IsEmpty() || !mediaStream.get()) {
    Local<Value> empty = Null(isolate);
    return scope.Escape(empty);
  }

  Local<Object> ret = instance->NewInstance(0, argv);
  MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, ret, "MediaStream");

  self->_stream = mediaStream;

  // TODO(): Implement This

  return scope.Escape(ret);
}

MediaStream::MediaStream() {

}

MediaStream::~MediaStream() {

}

void MediaStream::New(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();
  HandleScope scope(isolate);

  if (args.IsConstructCall()) {
    MediaStream* mediaStream = new MediaStream();
    mediaStream->Wrap(isolate, args.This(), "MediaStream");
    return args.GetReturnValue().Set(args.This());
  }

  isolate->ThrowException(Exception::Error(String::NewFromUtf8(isolate, "Internal Error")));
}

void MediaStream::AddTrack(const FunctionCallbackInfo<Value>& args) {
  //Isolate *isolate = args.GetIsolate();
  //MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, args.This(), "MediaStream");

  // TODO(): Implement This
}

void MediaStream::Clone(const FunctionCallbackInfo<Value>& args) {
  //Isolate *isolate = args.GetIsolate();
  //MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, args.This(), "MediaStream");

  // TODO(): Implement This
}

void MediaStream::GetTrackById(const FunctionCallbackInfo<Value>& args) {
  //Isolate *isolate = args.GetIsolate();
  //MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, args.This(), "MediaStream");

  // TODO(): Implement This
}

void MediaStream::GetAudioTracks(const FunctionCallbackInfo<Value>& args) {
  //Isolate *isolate = args.GetIsolate();
  //MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, args.This(), "MediaStream");

  // TODO(): Implement This
}

void MediaStream::GetVideoTracks(const FunctionCallbackInfo<Value>& args) {
  //Isolate *isolate = args.GetIsolate();
  //MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, args.This(), "MediaStream");

  // TODO(): Implement This
}

void MediaStream::RemoveTrack(const FunctionCallbackInfo<Value>& args) {
  //Isolate *isolate = args.GetIsolate();
  //MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, args.This(), "MediaStream");

  // TODO(): Implement This
}

void MediaStream::GetEnded(Local<String> property,
                           const PropertyCallbackInfo<Value> &info)
{
  //Isolate *isolate = args.GetIsolate();
  //MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, args.This(), "MediaStream");

  // TODO(): Implement This
}
void MediaStream::GetId(Local<String> property,
                        const PropertyCallbackInfo<Value> &info)
{
  //Isolate *isolate = args.GetIsolate();
  //MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, args.This(), "MediaStream");

  // TODO(): Implement This
}

void MediaStream::GetOnAddTrack(Local<String> property,
                                const PropertyCallbackInfo<Value> &info)
{
  Isolate *isolate = info.GetIsolate();
  MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, info.Holder(), "MediaStream");
  info.GetReturnValue().Set(Local<Function>::New(isolate, self->_onaddtrack));
}

void MediaStream::GetOnRemoveTrack(Local<String> property,
                                   const PropertyCallbackInfo<Value> &info)
{
  Isolate *isolate = info.GetIsolate();
  MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, info.Holder(), "MediaStream");
  info.GetReturnValue().Set(Local<Function>::New(isolate, self->_onremovetrack));
}

void MediaStream::GetOnEnded(Local<String> property,
                             const PropertyCallbackInfo<Value> &info)
{
  Isolate *isolate = info.GetIsolate();
  MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, info.Holder(), "MediaStream");
  info.GetReturnValue().Set(Local<Function>::New(isolate, self->_onended));
}

void MediaStream::ReadOnly(Local<String> property,
                           Local<Value> value,
                           const PropertyCallbackInfo<void> &info)
{

}

void MediaStream::SetOnAddTrack(Local<String> property,
                                Local<Value> value,
                                const PropertyCallbackInfo<void> &info)
{
  Isolate *isolate = info.GetIsolate();
  MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, info.Holder(), "MediaStream");

  if (!value.IsEmpty() && value->IsFunction()) {
    self->_onaddtrack.Reset(isolate, Local<Function>::Cast(value));
  }
  else {
    self->_onaddtrack.Reset();
  }
}

void MediaStream::SetOnRemoveTrack(Local<String> property,
                                   Local<Value> value,
                                   const PropertyCallbackInfo<void> &info)
{
  Isolate *isolate = info.GetIsolate();
  MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, info.Holder(), "MediaStream");

  if (!value.IsEmpty() && value->IsFunction()) {
    self->_onremovetrack.Reset(isolate, Local<Function>::Cast(value));
  }
  else {
    self->_onremovetrack.Reset();
  }
}

void MediaStream::SetOnEnded(Local<String> property,
                             Local<Value> value,
                             const PropertyCallbackInfo<void> &info)
{
  Isolate *isolate = info.GetIsolate();
  MediaStream *self = RTCWrap::Unwrap<MediaStream>(isolate, info.Holder(), "MediaStream");

  if (!value.IsEmpty() && value->IsFunction()) {
    self->_onended.Reset(isolate, Local<Function>::Cast(value));
  }
  else {
    self->_onended.Reset();
  }
}

void MediaStream::On(Event *event) {

}
<|endoftext|>


<commit_before>#include "image_io.h"
#include "../texture.h"

#include "OpenImageIO/imageio.h"

namespace Baikal
{
    class Oiio : public ImageIo
    {
    public:
        Texture::Ptr LoadImage(std::string const& filename) const override;
        void SaveImage(std::string const& filename, Texture::Ptr texture) const override;
    };

    static Texture::Format GetTextureFormat(OIIO_NAMESPACE::ImageSpec const& spec)
    {
        OIIO_NAMESPACE_USING

        if (spec.format.basetype == TypeDesc::UINT8)
            return Texture::Format::kRgba8;
        else if (spec.format.basetype == TypeDesc::HALF)
            return Texture::Format::kRgba16;
        else
            return Texture::Format::kRgba32;
    }

    static OIIO_NAMESPACE::TypeDesc GetTextureFormat(Texture::Format fmt)
    {
        OIIO_NAMESPACE_USING

        if (fmt == Texture::Format::kRgba8)
            return  TypeDesc::UINT8;
        else if (fmt == Texture::Format::kRgba16)
            return TypeDesc::HALF;
        else
            return TypeDesc::FLOAT;
    }

    Texture::Ptr Oiio::LoadImage(const std::string &filename) const
    {
        OIIO_NAMESPACE_USING

        std::unique_ptr<ImageInput> input{ImageInput::open(filename)};

        if (!input)
        {
            throw std::runtime_error("Can't load " + filename + " image");
        }

        ImageSpec const& spec = input->spec();

        auto fmt = GetTextureFormat(spec);
        char* texturedata = nullptr;

        if (fmt == Texture::Format::kRgba8)
        {
            auto size = spec.width * spec.height * spec.depth * 4;

            texturedata = new char[size];

            // Read data to storage
            if (spec.nchannels == 1)
            {
                input->read_image(TypeDesc::UINT8, texturedata, 4 * sizeof(char));
                // set B, G and A components to
                for (auto i = 0u; i < size; i += 4)
                {
                    texturedata[i + 1] = texturedata[i];
                    texturedata[i + 2] = texturedata[i];
                    texturedata[i + 3] = texturedata[i];
                }

            }
            else
            {
                input->read_image(TypeDesc::UINT8, texturedata, sizeof(char) * 4);
            }

            // Close handle
            input->close();
        }
        else if (fmt == Texture::Format::kRgba16)
        {
            auto size = spec.width * spec.height * spec.depth * sizeof(float) * 2;

            // Resize storage
            texturedata = new char[size];

            // Read data to storage
            input->read_image(TypeDesc::HALF, texturedata, sizeof(float) * 2);

            // Close handle
            input->close();
        }
        else
        {
            auto size = spec.width * spec.height * spec.depth * sizeof(RadeonRays::float3);

            // Resize storage
            texturedata = new char[size];

            // Read data to storage
            input->read_image(TypeDesc::FLOAT, texturedata, sizeof(RadeonRays::float3));

            // Close handle
            input->close();
        }

        //
        return Texture::Create(texturedata, RadeonRays::int2(spec.width, spec.height), fmt);;
    }

    void Oiio::SaveImage(std::string const& filename, Texture::Ptr texture) const
    {
        OIIO_NAMESPACE_USING;

        std::unique_ptr<ImageOutput> out{ImageOutput::create(filename)};

        if (!out)
        {
            throw std::runtime_error("Can't create image file on disk");
        }

        auto dim = texture->GetSize();
        auto fmt = GetTextureFormat(texture->GetFormat());

        ImageSpec spec(dim.x, dim.y, 4, fmt);

        out->open(filename, spec);

        out->write_image(fmt, texture->GetData());

        out->close();
    }

    std::unique_ptr<ImageIo> ImageIo::CreateImageIo()
    {
        return std::make_unique<Oiio>();
    }
}
<commit_msg>Moved read function<commit_after>#include "image_io.h"
#include "../texture.h"

#include "OpenImageIO/imageio.h"

namespace Baikal
{
    class Oiio : public ImageIo
    {
    public:
        Texture::Ptr LoadImage(std::string const& filename) const override;
        void SaveImage(std::string const& filename, Texture::Ptr texture) const override;
    };

    static Texture::Format GetTextureFormat(OIIO_NAMESPACE::ImageSpec const& spec)
    {
        OIIO_NAMESPACE_USING

        if (spec.format.basetype == TypeDesc::UINT8)
            return Texture::Format::kRgba8;
        else if (spec.format.basetype == TypeDesc::HALF)
            return Texture::Format::kRgba16;
        else
            return Texture::Format::kRgba32;
    }

    static OIIO_NAMESPACE::TypeDesc GetTextureFormat(Texture::Format fmt)
    {
        OIIO_NAMESPACE_USING

        if (fmt == Texture::Format::kRgba8)
            return  TypeDesc::UINT8;
        else if (fmt == Texture::Format::kRgba16)
            return TypeDesc::HALF;
        else
            return TypeDesc::FLOAT;
    }

    Texture::Ptr Oiio::LoadImage(const std::string &filename) const
    {
        OIIO_NAMESPACE_USING

        std::unique_ptr<ImageInput> input{ImageInput::open(filename)};

        if (!input)
        {
            throw std::runtime_error("Can't load " + filename + " image");
        }

        ImageSpec const& spec = input->spec();

        auto fmt = GetTextureFormat(spec);
        char* texturedata = nullptr;

        if (fmt == Texture::Format::kRgba8)
        {
            auto size = spec.width * spec.height * spec.depth * 4;

            texturedata = new char[size];

            // Read data to storage
            input->read_image(TypeDesc::UINT8, texturedata, sizeof(char) * 4);

            if (spec.nchannels == 1)
            {
                // set B, G and A components to
                for (auto i = 0u; i < size; i += 4)
                {
                    texturedata[i + 1] = texturedata[i];
                    texturedata[i + 2] = texturedata[i];
                    texturedata[i + 3] = texturedata[i];
                }

            }

            // Close handle
            input->close();
        }
        else if (fmt == Texture::Format::kRgba16)
        {
            auto size = spec.width * spec.height * spec.depth * sizeof(float) * 2;

            // Resize storage
            texturedata = new char[size];

            // Read data to storage
            input->read_image(TypeDesc::HALF, texturedata, sizeof(float) * 2);

            // Close handle
            input->close();
        }
        else
        {
            auto size = spec.width * spec.height * spec.depth * sizeof(RadeonRays::float3);

            // Resize storage
            texturedata = new char[size];

            // Read data to storage
            input->read_image(TypeDesc::FLOAT, texturedata, sizeof(RadeonRays::float3));

            // Close handle
            input->close();
        }

        //
        return Texture::Create(texturedata, RadeonRays::int2(spec.width, spec.height), fmt);;
    }

    void Oiio::SaveImage(std::string const& filename, Texture::Ptr texture) const
    {
        OIIO_NAMESPACE_USING;

        std::unique_ptr<ImageOutput> out{ImageOutput::create(filename)};

        if (!out)
        {
            throw std::runtime_error("Can't create image file on disk");
        }

        auto dim = texture->GetSize();
        auto fmt = GetTextureFormat(texture->GetFormat());

        ImageSpec spec(dim.x, dim.y, 4, fmt);

        out->open(filename, spec);

        out->write_image(fmt, texture->GetData());

        out->close();
    }

    std::unique_ptr<ImageIo> ImageIo::CreateImageIo()
    {
        return std::make_unique<Oiio>();
    }
}
<|endoftext|>


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

#include "common/environment.h"
#include "common/directory.h"
#include "common/path.h"

#include "preproc/env.h"

#include "api/console.h"

#include "config.h"

#if OS_IS_WINDOWS
#   include <windows.h>
#else
#   include <unistd.h>
#endif

namespace Path
{
    std::string Get( const std::string &path, Type type /*= Type::Game */ )
    {
        std::string from;
        bool resolve = true;

        switch ( type )
        {
        case Path::Type::Program:
            from = Path::GetProgramDirectory();
            break;

        case Path::Type::Data:
            from = Path::GetProgramDataDirectory();
            break;

        case Path::Type::SharedData:
            from = Path::GetProgramSharedDataDirectory();
            break;

        case Path::Type::Temp:
            from = Path::GetProgramTempDirectory();
            break;

        case Path::Type::Editor:
            from = Path::GetProgramDirectory();
            break;

        case Path::Type::None:
            resolve = false;
            break;
        }

        return resolve ? Path::ResolveRelative( from, path ) : path;
    }

    std::string ResolveRelative( const std::string &from, const std::string &to, bool sameRoot /*= true */ )
    {
        if ( sameRoot )
        {
            // Just add the relative path to the from path an normalise :)
            return Canonical( FixStyle( boost::filesystem::path( FixStyle( from ) ).parent_path().generic_string() ) + to );
        }
        else
        {
            // Cheers - http://stackoverflow.com/questions/10167382/boostfilesystem-get-relative-path

            boost::filesystem::path fsFrom, fsTo, result;

            fsFrom  = boost::filesystem::absolute( from ).parent_path();
            fsTo    = boost::filesystem::absolute( to );

            boost::filesystem::path::const_iterator itrFrom( fsFrom.begin() ), itrTo( fsTo.begin() );

            // Find common base
            /// @todo itrTo != toEnd always true
            for ( boost::filesystem::path::const_iterator toEnd( fsTo.end() ), fromEnd( fsFrom.end() ) ;
                    itrTo != toEnd && itrFrom != fromEnd && *itrFrom == *itrTo; ++itrFrom, ++itrTo );

            // Navigate backwards in directory to reach previously found base
            for ( boost::filesystem::path::const_iterator fromEnd( fsFrom.end() ); itrFrom != fromEnd; ++itrFrom )
            {
                if ( ( *itrFrom ) != "." )
                {
                    result /= "..";
                }
            }

            // Now navigate down the directory branch
            for ( ; itrTo != fsTo.end() ; ++itrTo )
            {
                result /= *itrTo;
            }

            return Canonical( result.generic_string() );
        }
    }

    std::string FixStyle( const std::string &filePath )
    {
        const boost::filesystem::path path( filePath );
        std::string newPath = path.generic_string();

        if ( !( path.has_stem() && path.has_extension() ) )
        {
            if ( path.empty() || newPath.back() != '/' )
            {
                newPath += '/';
            }
        }

#if !(OS_IS_WINDOWS)
        newPath = String::Replace( newPath, "\\", "/" );
        newPath = String::Replace( newPath, "//", "/" );
#endif
        return newPath;
    }

    std::string Canonical( const std::string &path, bool absolute /*= false */ )
    {
        std::cout << path << std::endl;

        if ( ( path == "." || path == "./" ) && !absolute )
        {
            return path;
        }

        // Again Cheers - http://stackoverflow.com/questions/1746136/how-do-i-normalize-a-pathname-using-boostfilesystem
        boost::filesystem::path fsPath( path );

        if ( absolute )
        {
            fsPath = boost::filesystem::absolute( fsPath );
        }

        boost::filesystem::path result;

        for ( auto it = fsPath.begin(), end = fsPath.end(); it != end; ++it )
        {
            const std::string part = it->generic_string();

            if ( part == ".." )
            {
                if ( result.filename() == ".." )
                {
                    result /= *it;
                }
                else
                {
                    if ( result != "" )
                    {
                        result = result.parent_path();
                    }
                    else
                    {
                        result /= "..";
                    }
                }
            }
            else if ( part == "." )
            {
                // Ignore
            }
            else
            {
                // Just cat other path entries
                result /= *it;
            }
        }

        return FixStyle( result.generic_string() );
    }

    bool IsParent( const std::string &from, const std::string &to )
    {
        const std::string canFrom = Canonical( from, true );
        const std::string canTo = Canonical( to, true );
        const std::string relative = Canonical( canFrom + ResolveRelative( canFrom, canTo, false ), true );

        return relative.find( canFrom ) == 0;
    }

    std::string GetFileName( const std::string &path, const bool stripExtension /*= false */ )
    {
        const boost::filesystem::path fsPath( FixStyle( path ) );
        std::string filename;

        if ( !stripExtension )
        {
            filename = fsPath.filename().generic_string();
        }
        else
        {
            filename = fsPath.stem().generic_string();
        }

        return filename;
    }

    std::string GetDirectory( const std::string &path )
    {
        return FixStyle( boost::filesystem::path( path ).parent_path().generic_string() );
    }

    std::string GetExtension( const std::string &filepath, const bool addDot /*= false */ )
    {
        const std::string fullExtension = boost::filesystem::path( filepath ).extension().generic_string();

        return addDot || fullExtension == "" ? fullExtension : fullExtension.substr( 1 );
    }

    bool HasExtension( const std::string &filepath )
    {
        return boost::filesystem::path( filepath ).has_extension();
    }

    std::string GetUniqueFileName( const std::string &extension /*= ".tmp" */ )
    {
        return FixStyle( boost::filesystem::unique_path( "%%%%-%%%%-%%%%-%%%%" + extension ).generic_string() );
    }

    std::string GetUniqueDirectory()
    {
        return FixStyle( boost::filesystem::unique_path( "%%%%-%%%%-%%%%" ).generic_string() );
    }

    std::string GetTempDirectory()
    {
        return FixStyle( boost::filesystem::temp_directory_path().generic_string() );
    }

    std::string GetExeDirectory()
    {
        return FixStyle( boost::filesystem::path( GetExeFile() ).parent_path().generic_string() );
    }

    std::string GetExeFile()
    {
#if OS_IS_WINDOWS
        char result[ MAX_PATH ];
        return Canonical( std::string( result, GetModuleFileNameA( nullptr, result, MAX_PATH ) ) );
#elif OS_IS_LINUX
        char result[ PATH_MAX ];
        size_t count = readlink( "/proc/self/exe", result, PATH_MAX );
        return std::string( result, ( count > 0 ) ? count : 0 );
#else
#error
#endif
    }

    std::string GetDataDirectory()
    {
#if OS_IS_WINDOWS
        return FixStyle( Environment::GetVariable( "APPDATA" ) );
#elif OS_IS_LINUX
        return FixStyle( "~/local/share/" );
#elif OS_IS_MACOS
        return "~/Library/Application Support/";
#endif
    }

    std::string GetSharedDataDirectory()
    {
#if OS_IS_WINDOWS
        return FixStyle( Environment::GetVariable( "ALLUSERSPROFILE" ) );
#elif OS_IS_LINUX
        return "/usr/local/";
#elif OS_IS_MACOS
        return "/usr/local/";
#endif
    }

    std::string GetProgramDirectory()
    {
        return GetExeDirectory();
    }

    std::string GetProgramTempDirectory()
    {
        return String::Format( "%s%s/%s/", GetTempDirectory(), std::string( PROGRAM_COMPANY ), std::string( PROGRAM_NAME ) );
    }

    std::string GetProgramDataDirectory()
    {
        return String::Format( "%s%s/%s/", GetDataDirectory(), std::string( PROGRAM_COMPANY ), std::string( PROGRAM_NAME ) );
    }

    std::string GetProgramSharedDataDirectory()
    {
        return String::Format( "%s%s/%s/", GetSharedDataDirectory(),
                               std::string( PROGRAM_COMPANY ),
                               std::string( PROGRAM_NAME ) );
    }

    std::vector< boost::filesystem::path > List( const std::string &directory, bool recursive /*= false */ )
    {
        std::vector< boost::filesystem::path > contents;

        if ( !Directory::Exists( directory ) )
        {
            return contents;
        }

        if ( recursive )
        {
            boost::filesystem::recursive_directory_iterator it( directory ), end;

            for ( ; it != end; ++it )
            {
                contents.push_back( *it );
            }
        }
        else
        {
            boost::filesystem::directory_iterator it( directory ), end;

            for ( ; it != end; ++it )
            {
                contents.push_back( *it );
            }
        }

        return contents;
    }

    std::vector< std::string > ListContent( const std::string &directory, bool recursive /*= false */ )
    {
        const std::vector< boost::filesystem::path > contents = List( directory, recursive );
        std::vector< std::string > result;
        result.reserve( contents.size() );

        for ( auto it = contents.begin(), end = contents.end(); it != end; ++it )
        {
            result.push_back( FixStyle( it->generic_string() ) );
        }

        return result;
    }

    std::string GetWorkingDirectory()
    {
        return Path::FixStyle( boost::filesystem::current_path().generic_string() );
    }

    bool SetWorkingDirectory( const std::string &workingDirectory )
    {
        bool success = true;

        try
        {
            boost::filesystem::current_path( workingDirectory );
        }
        catch ( boost::filesystem::filesystem_error & )
        {
            success = false;
        }

        return success;
    }

    void DeleteAll( const std::string &path )
    {
        boost::filesystem::remove_all( path );
    }

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

#include "common/environment.h"
#include "common/directory.h"
#include "common/path.h"

#include "preproc/env.h"

#include "api/console.h"

#include "config.h"

#if OS_IS_WINDOWS
#   include <windows.h>
#else
#   include <unistd.h>
#endif

namespace Path
{
    std::string Get( const std::string &path, Type type /*= Type::Game */ )
    {
        std::string from;
        bool resolve = true;

        switch ( type )
        {
        case Path::Type::Program:
            from = Path::GetProgramDirectory();
            break;

        case Path::Type::Data:
            from = Path::GetProgramDataDirectory();
            break;

        case Path::Type::SharedData:
            from = Path::GetProgramSharedDataDirectory();
            break;

        case Path::Type::Temp:
            from = Path::GetProgramTempDirectory();
            break;

        case Path::Type::Editor:
            from = Path::GetProgramDirectory();
            break;

        case Path::Type::None:
            resolve = false;
            break;
        }

        return resolve ? Path::ResolveRelative( from, path ) : path;
    }

    std::string ResolveRelative( const std::string &from, const std::string &to, bool sameRoot /*= true */ )
    {
        if ( sameRoot )
        {
            // Just add the relative path to the from path an normalise :)
            return Canonical( FixStyle( boost::filesystem::path( Canonical( from ) ).parent_path().generic_string() ) + to );
        }
        else
        {
            // Cheers - http://stackoverflow.com/questions/10167382/boostfilesystem-get-relative-path

            boost::filesystem::path fsFrom, fsTo, result;

            fsFrom  = boost::filesystem::absolute( from ).parent_path();
            fsTo    = boost::filesystem::absolute( to );

            boost::filesystem::path::const_iterator itrFrom( fsFrom.begin() ), itrTo( fsTo.begin() );

            // Find common base
            /// @todo itrTo != toEnd always true
            for ( boost::filesystem::path::const_iterator toEnd( fsTo.end() ), fromEnd( fsFrom.end() ) ;
                    itrTo != toEnd && itrFrom != fromEnd && *itrFrom == *itrTo; ++itrFrom, ++itrTo );

            // Navigate backwards in directory to reach previously found base
            for ( boost::filesystem::path::const_iterator fromEnd( fsFrom.end() ); itrFrom != fromEnd; ++itrFrom )
            {
                if ( ( *itrFrom ) != "." )
                {
                    result /= "..";
                }
            }

            // Now navigate down the directory branch
            for ( ; itrTo != fsTo.end() ; ++itrTo )
            {
                result /= *itrTo;
            }

            return Canonical( result.generic_string() );
        }
    }

    std::string FixStyle( const std::string &filePath )
    {
        const boost::filesystem::path path( filePath );
        std::string newPath = path.generic_string();

        if ( !( path.has_stem() && path.has_extension() ) )
        {
            if ( path.empty() || newPath.back() != '/' )
            {
                newPath += '/';
            }
        }

#if !(OS_IS_WINDOWS)
        newPath = String::Replace( newPath, "\\", "/" );
        newPath = String::Replace( newPath, "//", "/" );
#endif
        return newPath;
    }

    std::string Canonical( const std::string &path, bool absolute /*= false */ )
    {
        std::cout << path << std::endl;

        if ( ( path == "." || path == "./" ) && !absolute )
        {
            return path;
        }

        // Again Cheers - http://stackoverflow.com/questions/1746136/how-do-i-normalize-a-pathname-using-boostfilesystem
        boost::filesystem::path fsPath( path );

        if ( absolute )
        {
            fsPath = boost::filesystem::absolute( fsPath );
        }

        boost::filesystem::path result;

        for ( auto it = fsPath.begin(), end = fsPath.end(); it != end; ++it )
        {
            const std::string part = it->generic_string();

            if ( part == ".." )
            {
                if ( result.filename() == ".." )
                {
                    result /= *it;
                }
                else
                {
                    if ( result != "" )
                    {
                        result = result.parent_path();
                    }
                    else
                    {
                        result /= "..";
                    }
                }
            }
            else if ( part == "." )
            {
                // Ignore
            }
            else
            {
                // Just cat other path entries
                result /= *it;
            }
        }

        return FixStyle( result.generic_string() );
    }

    bool IsParent( const std::string &from, const std::string &to )
    {
        const std::string canFrom = Canonical( from, true );
        const std::string canTo = Canonical( to, true );
        const std::string relative = Canonical( canFrom + ResolveRelative( canFrom, canTo, false ), true );

        return relative.find( canFrom ) == 0;
    }

    std::string GetFileName( const std::string &path, const bool stripExtension /*= false */ )
    {
        const boost::filesystem::path fsPath( FixStyle( path ) );
        std::string filename;

        if ( !stripExtension )
        {
            filename = fsPath.filename().generic_string();
        }
        else
        {
            filename = fsPath.stem().generic_string();
        }

        return filename;
    }

    std::string GetDirectory( const std::string &path )
    {
        return FixStyle( boost::filesystem::path( path ).parent_path().generic_string() );
    }

    std::string GetExtension( const std::string &filepath, const bool addDot /*= false */ )
    {
        const std::string fullExtension = boost::filesystem::path( filepath ).extension().generic_string();

        return addDot || fullExtension == "" ? fullExtension : fullExtension.substr( 1 );
    }

    bool HasExtension( const std::string &filepath )
    {
        return boost::filesystem::path( filepath ).has_extension();
    }

    std::string GetUniqueFileName( const std::string &extension /*= ".tmp" */ )
    {
        return FixStyle( boost::filesystem::unique_path( "%%%%-%%%%-%%%%-%%%%" + extension ).generic_string() );
    }

    std::string GetUniqueDirectory()
    {
        return FixStyle( boost::filesystem::unique_path( "%%%%-%%%%-%%%%" ).generic_string() );
    }

    std::string GetTempDirectory()
    {
        return FixStyle( boost::filesystem::temp_directory_path().generic_string() );
    }

    std::string GetExeDirectory()
    {
        return FixStyle( boost::filesystem::path( GetExeFile() ).parent_path().generic_string() );
    }

    std::string GetExeFile()
    {
#if OS_IS_WINDOWS
        char result[ MAX_PATH ];
        return Canonical( std::string( result, GetModuleFileNameA( nullptr, result, MAX_PATH ) ) );
#elif OS_IS_LINUX
        char result[ PATH_MAX ];
        size_t count = readlink( "/proc/self/exe", result, PATH_MAX );
        return std::string( result, ( count > 0 ) ? count : 0 );
#else
#error
#endif
    }

    std::string GetDataDirectory()
    {
#if OS_IS_WINDOWS
        return FixStyle( Environment::GetVariable( "APPDATA" ) );
#elif OS_IS_LINUX
        return FixStyle( "~/local/share/" );
#elif OS_IS_MACOS
        return "~/Library/Application Support/";
#endif
    }

    std::string GetSharedDataDirectory()
    {
#if OS_IS_WINDOWS
        return FixStyle( Environment::GetVariable( "ALLUSERSPROFILE" ) );
#elif OS_IS_LINUX
        return "/usr/local/";
#elif OS_IS_MACOS
        return "/usr/local/";
#endif
    }

    std::string GetProgramDirectory()
    {
        return GetExeDirectory();
    }

    std::string GetProgramTempDirectory()
    {
        return String::Format( "%s%s/%s/", GetTempDirectory(), std::string( PROGRAM_COMPANY ), std::string( PROGRAM_NAME ) );
    }

    std::string GetProgramDataDirectory()
    {
        return String::Format( "%s%s/%s/", GetDataDirectory(), std::string( PROGRAM_COMPANY ), std::string( PROGRAM_NAME ) );
    }

    std::string GetProgramSharedDataDirectory()
    {
        return String::Format( "%s%s/%s/", GetSharedDataDirectory(),
                               std::string( PROGRAM_COMPANY ),
                               std::string( PROGRAM_NAME ) );
    }

    std::vector< boost::filesystem::path > List( const std::string &directory, bool recursive /*= false */ )
    {
        std::vector< boost::filesystem::path > contents;

        if ( !Directory::Exists( directory ) )
        {
            return contents;
        }

        if ( recursive )
        {
            boost::filesystem::recursive_directory_iterator it( directory ), end;

            for ( ; it != end; ++it )
            {
                contents.push_back( *it );
            }
        }
        else
        {
            boost::filesystem::directory_iterator it( directory ), end;

            for ( ; it != end; ++it )
            {
                contents.push_back( *it );
            }
        }

        return contents;
    }

    std::vector< std::string > ListContent( const std::string &directory, bool recursive /*= false */ )
    {
        const std::vector< boost::filesystem::path > contents = List( directory, recursive );
        std::vector< std::string > result;
        result.reserve( contents.size() );

        for ( auto it = contents.begin(), end = contents.end(); it != end; ++it )
        {
            result.push_back( FixStyle( it->generic_string() ) );
        }

        return result;
    }

    std::string GetWorkingDirectory()
    {
        return Path::FixStyle( boost::filesystem::current_path().generic_string() );
    }

    bool SetWorkingDirectory( const std::string &workingDirectory )
    {
        bool success = true;

        try
        {
            boost::filesystem::current_path( workingDirectory );
        }
        catch ( boost::filesystem::filesystem_error & )
        {
            success = false;
        }

        return success;
    }

    void DeleteAll( const std::string &path )
    {
        boost::filesystem::remove_all( path );
    }

}<|endoftext|>


<commit_before><commit_msg>fix one warning<commit_after><|endoftext|>


<commit_before><commit_msg>Remove assignments from conditional expression<commit_after><|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <algorithm>
#include <chrono>
#include <memory>
#include <cmath>

#include <SmurffCpp/DataMatrices/Data.h>
#include <SmurffCpp/ConstVMatrixIterator.hpp>

#include <SmurffCpp/Types.h>

#include <SmurffCpp/Model.h>
#include <SmurffCpp/result.h>

#include <SmurffCpp/Utils/Error.h>
#include <SmurffCpp/Utils/SaveState.h>
#include <SmurffCpp/Utils/StringUtils.h>

namespace smurff {

Result::Result() {}

Result::Result(const DataConfig &Y, int nsamples)
    : m_dims(Y.getDims())
{
   if(Y.isDense())
   {
      THROWERROR("test data should be sparse");
   }

   if (Y.isMatrix()) set(Y.getSparseMatrixData(), nsamples);
   else set(Y.getSparseTensorData(), nsamples);
}

//Y - test sparse matrix
Result::Result(const SparseMatrix &Y, int nsamples)
    : m_dims({Y.rows(), Y.cols()}), m_nsamples(nsamples)
{
    set(Y, nsamples);
}

//Y - test sparse tensor
Result::Result(const SparseTensor &Y, int nsamples)
    : m_dims(Y.getDims())
{
    set(Y, nsamples);
}

Result::Result(PVec<> lo, PVec<> hi, double value, int nsamples)
    : m_dims(hi - lo), m_nsamples(nsamples)
{

   for(auto it = PVecIterator(lo, hi); !it.done(); ++it)
   {
      m_predictions.push_back(ResultItem(*it, value, nsamples));
   }
}

void Result::set(const SparseMatrix &Y, int nsamples)
{
   for (int k = 0; k < Y.outerSize(); ++k)
      for (SparseMatrix::InnerIterator it(Y,k); it; ++it)
      {
         PVec<> pos = {it.row(), it.col()};
         m_predictions.push_back(ResultItem(pos, it.value(), nsamples));
      }
}

void Result::set(const SparseTensor &Y, int nsamples)
{
   for(std::uint64_t i = 0; i < Y.getNNZ(); i++)
   {
      const auto p = Y.get(i);
      m_predictions.push_back(ResultItem(p.first, p.second, nsamples));
   }
}

void Result::init()
{
   total_pos = 0;
   if (classify)
   {
      for (const auto &p : m_predictions)
      {
         int is_positive = p.val > threshold;
         total_pos += is_positive;
      }
   }
}

std::vector<SparseMatrix> Result::asMatrixVector() const
{
   std::vector<SparseMatrix> ret;

   for(int i=0; i<m_nsamples; ++i)
   {
      auto pred = toMatrix([i](const ResultItem &p) { return p.pred_all.at(i); });
      ret.push_back(*pred);
   }

   return ret;
}

//--- output model to files

template<typename Accessor>
std::shared_ptr<const SparseMatrix> Result::toMatrix(const Accessor &acc) const
{
   auto ret = std::make_shared<SparseMatrix>(m_dims.at(0), m_dims.at(1));

   std::vector<Eigen::Triplet<smurff::float_type>> triplets;

   for (const auto &p : m_predictions)
      triplets.push_back({ (int)p.coords.at(0), (int)p.coords.at(1), acc(p) });

   ret->setFromTriplets(triplets.begin(), triplets.end());
   return ret;
}

void Result::save(SaveState &sf) const
{
   if (isEmpty())
      return;

   if (m_dims.size() == 2)
   {
      auto pred_avg = toMatrix([](const ResultItem &p) { return p.pred_avg; });
      auto pred_var = toMatrix([](const ResultItem &p) { return p.var; });
      auto pred_1sample = toMatrix([](const ResultItem &p) { return p.pred_1sample; });

      sf.putPredAvgVar(*pred_avg, *pred_var, *pred_1sample);
   }

   sf.putPredState(rmse_avg, rmse_1sample, auc_avg, auc_1sample, sample_iter, burnin_iter);
}

void Result::toCsv(std::string filename) const
{
   std::ofstream predFile;
   predFile.open(filename, std::ios::out);
   THROWERROR_ASSERT_MSG(predFile.is_open(), "Error opening file: " + filename);

   for (std::size_t d = 0; d < m_dims.size(); d++)
      predFile << "coord" << d << ",";

   predFile << "y,pred_1samp,pred_avg,var" << std::endl;

   for (std::vector<ResultItem>::const_iterator it = m_predictions.begin(); it != m_predictions.end(); it++)
   {
      it->coords.save(predFile)
          << "," << std::to_string(it->val)
          << "," << std::to_string(it->pred_1sample)
          << "," << std::to_string(it->pred_avg)
          << "," << std::to_string(it->var)
          << std::endl;
   }

   predFile.close();
}

void Result::restore(const SaveState &sf)
{
   sf.getPredState(rmse_avg, rmse_1sample, auc_avg, auc_1sample, sample_iter, burnin_iter);
}

//--- update RMSE and AUC

//model - holds samples (U matrices)
void Result::update(const Model &model, bool burnin)
{
   if (m_predictions.empty())
      return;

   const size_t NNZ = m_predictions.size();

   if (burnin)
   {
      double se_1sample = 0.0;

      #pragma omp parallel for schedule(guided) reduction(+:se_1sample)
      for(size_t k = 0; k < m_predictions.size(); ++k)
      {
         auto &t = m_predictions.operator[](k);
         t.pred_1sample = model.predict(t.coords); //dot product of i'th columns in each U matrix
         se_1sample += std::pow(t.val - t.pred_1sample, 2);
      }

      burnin_iter++;
      rmse_1sample = std::sqrt(se_1sample / NNZ);

      if (classify)
      {
         auc_1sample = calc_auc(m_predictions, threshold,
               [](const ResultItem &a, const ResultItem &b) { return a.pred_1sample < b.pred_1sample;});
      }
   }
   else
   {
      double se_1sample = 0.0;
      double se_avg = 0.0;

      #pragma omp parallel for schedule(guided) reduction(+:se_1sample, se_avg)
      for(size_t k = 0; k < m_predictions.size(); ++k)
      {
         auto &t = m_predictions.operator[](k);
         const double pred = model.predict(t.coords); //dot product of i'th columns in each U matrix
         t.update(pred);

         se_1sample += std::pow(t.val - pred, 2);
         se_avg += std::pow(t.val - t.pred_avg, 2);
      }

      sample_iter++;
      rmse_1sample = std::sqrt(se_1sample / NNZ);
      rmse_avg = std::sqrt(se_avg / NNZ);

      if (classify)
      {
         auc_1sample = calc_auc(m_predictions, threshold,
               [](const ResultItem &a, const ResultItem &b) { return a.pred_1sample < b.pred_1sample;});

         auc_avg = calc_auc(m_predictions, threshold,
               [](const ResultItem &a, const ResultItem &b) { return a.pred_avg < b.pred_avg;});
      }
   }
}

std::ostream &Result::info(std::ostream &os, std::string indent) const
{
   if (!m_predictions.empty())
   {
      std::uint64_t dtotal = 1;
      for(size_t d = 0; d < m_dims.size(); d++)
         dtotal *= m_dims[d];

      double test_fill_rate = 100. * m_predictions.size() / dtotal;

      os << indent << "Test data: " << m_predictions.size();

      os << " [";
      for(size_t d = 0; d < m_dims.size(); d++)
      {
         if(d == m_dims.size() - 1)
            os << m_dims[d];
         else
            os << m_dims[d] << " x ";
      }
      os << "]";

      os << " (" << test_fill_rate << "%)" << std::endl;

      if (classify)
      {
         double pos = 100. * (double)total_pos / (double)m_predictions.size();
         os << indent << "Binary classification threshold: " << threshold << std::endl;
         os << indent << "  " << pos << "% positives in test data" << std::endl;
      }
   }
   else
   {
      os << indent << "Test data: -" << std::endl;

      if (classify)
      {
         os << indent << "Binary classification threshold: " << threshold << std::endl;
         os << indent << "  " << "-" << "% positives in test data" << std::endl;
      }
   }

   return os;
}

bool Result::isEmpty() const
{
   return m_predictions.empty();
}
} // end namespace smurff
<commit_msg>FIX: missing m_nsamples init<commit_after>#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <algorithm>
#include <chrono>
#include <memory>
#include <cmath>

#include <SmurffCpp/DataMatrices/Data.h>
#include <SmurffCpp/ConstVMatrixIterator.hpp>

#include <SmurffCpp/Types.h>

#include <SmurffCpp/Model.h>
#include <SmurffCpp/result.h>

#include <SmurffCpp/Utils/Error.h>
#include <SmurffCpp/Utils/SaveState.h>
#include <SmurffCpp/Utils/StringUtils.h>

namespace smurff {

Result::Result() {}

Result::Result(const DataConfig &Y, int nsamples)
    : m_dims(Y.getDims())
{
   if(Y.isDense())
   {
      THROWERROR("test data should be sparse");
   }

   if (Y.isMatrix()) set(Y.getSparseMatrixData(), nsamples);
   else set(Y.getSparseTensorData(), nsamples);
}

//Y - test sparse matrix
Result::Result(const SparseMatrix &Y, int nsamples)
    : m_dims({Y.rows(), Y.cols()}), m_nsamples(nsamples)
{
    set(Y, nsamples);
}

//Y - test sparse tensor
Result::Result(const SparseTensor &Y, int nsamples)
    : m_dims(Y.getDims()), m_nsamples(nsamples)
{
    set(Y, nsamples);
}

Result::Result(PVec<> lo, PVec<> hi, double value, int nsamples)
    : m_dims(hi - lo), m_nsamples(nsamples)
{

   for(auto it = PVecIterator(lo, hi); !it.done(); ++it)
   {
      m_predictions.push_back(ResultItem(*it, value, nsamples));
   }
}

void Result::set(const SparseMatrix &Y, int nsamples)
{
   for (int k = 0; k < Y.outerSize(); ++k)
      for (SparseMatrix::InnerIterator it(Y,k); it; ++it)
      {
         PVec<> pos = {it.row(), it.col()};
         m_predictions.push_back(ResultItem(pos, it.value(), nsamples));
      }
}

void Result::set(const SparseTensor &Y, int nsamples)
{
   for(std::uint64_t i = 0; i < Y.getNNZ(); i++)
   {
      const auto p = Y.get(i);
      m_predictions.push_back(ResultItem(p.first, p.second, nsamples));
   }
}

void Result::init()
{
   total_pos = 0;
   if (classify)
   {
      for (const auto &p : m_predictions)
      {
         int is_positive = p.val > threshold;
         total_pos += is_positive;
      }
   }
}

std::vector<SparseMatrix> Result::asMatrixVector() const
{
   std::vector<SparseMatrix> ret;

   for(int i=0; i<m_nsamples; ++i)
   {
      auto pred = toMatrix([i](const ResultItem &p) { return p.pred_all.at(i); });
      ret.push_back(*pred);
   }

   return ret;
}

//--- output model to files

template<typename Accessor>
std::shared_ptr<const SparseMatrix> Result::toMatrix(const Accessor &acc) const
{
   auto ret = std::make_shared<SparseMatrix>(m_dims.at(0), m_dims.at(1));

   std::vector<Eigen::Triplet<smurff::float_type>> triplets;

   for (const auto &p : m_predictions)
      triplets.push_back({ (int)p.coords.at(0), (int)p.coords.at(1), acc(p) });

   ret->setFromTriplets(triplets.begin(), triplets.end());
   return ret;
}

void Result::save(SaveState &sf) const
{
   if (isEmpty())
      return;

   if (m_dims.size() == 2)
   {
      auto pred_avg = toMatrix([](const ResultItem &p) { return p.pred_avg; });
      auto pred_var = toMatrix([](const ResultItem &p) { return p.var; });
      auto pred_1sample = toMatrix([](const ResultItem &p) { return p.pred_1sample; });

      sf.putPredAvgVar(*pred_avg, *pred_var, *pred_1sample);
   }

   sf.putPredState(rmse_avg, rmse_1sample, auc_avg, auc_1sample, sample_iter, burnin_iter);
}

void Result::toCsv(std::string filename) const
{
   std::ofstream predFile;
   predFile.open(filename, std::ios::out);
   THROWERROR_ASSERT_MSG(predFile.is_open(), "Error opening file: " + filename);

   for (std::size_t d = 0; d < m_dims.size(); d++)
      predFile << "coord" << d << ",";

   predFile << "y,pred_1samp,pred_avg,var" << std::endl;

   for (std::vector<ResultItem>::const_iterator it = m_predictions.begin(); it != m_predictions.end(); it++)
   {
      it->coords.save(predFile)
          << "," << std::to_string(it->val)
          << "," << std::to_string(it->pred_1sample)
          << "," << std::to_string(it->pred_avg)
          << "," << std::to_string(it->var)
          << std::endl;
   }

   predFile.close();
}

void Result::restore(const SaveState &sf)
{
   sf.getPredState(rmse_avg, rmse_1sample, auc_avg, auc_1sample, sample_iter, burnin_iter);
}

//--- update RMSE and AUC

//model - holds samples (U matrices)
void Result::update(const Model &model, bool burnin)
{
   if (m_predictions.empty())
      return;

   const size_t NNZ = m_predictions.size();

   if (burnin)
   {
      double se_1sample = 0.0;

      #pragma omp parallel for schedule(guided) reduction(+:se_1sample)
      for(size_t k = 0; k < m_predictions.size(); ++k)
      {
         auto &t = m_predictions.operator[](k);
         t.pred_1sample = model.predict(t.coords); //dot product of i'th columns in each U matrix
         se_1sample += std::pow(t.val - t.pred_1sample, 2);
      }

      burnin_iter++;
      rmse_1sample = std::sqrt(se_1sample / NNZ);

      if (classify)
      {
         auc_1sample = calc_auc(m_predictions, threshold,
               [](const ResultItem &a, const ResultItem &b) { return a.pred_1sample < b.pred_1sample;});
      }
   }
   else
   {
      double se_1sample = 0.0;
      double se_avg = 0.0;

      #pragma omp parallel for schedule(guided) reduction(+:se_1sample, se_avg)
      for(size_t k = 0; k < m_predictions.size(); ++k)
      {
         auto &t = m_predictions.operator[](k);
         const double pred = model.predict(t.coords); //dot product of i'th columns in each U matrix
         t.update(pred);

         se_1sample += std::pow(t.val - pred, 2);
         se_avg += std::pow(t.val - t.pred_avg, 2);
      }

      sample_iter++;
      rmse_1sample = std::sqrt(se_1sample / NNZ);
      rmse_avg = std::sqrt(se_avg / NNZ);

      if (classify)
      {
         auc_1sample = calc_auc(m_predictions, threshold,
               [](const ResultItem &a, const ResultItem &b) { return a.pred_1sample < b.pred_1sample;});

         auc_avg = calc_auc(m_predictions, threshold,
               [](const ResultItem &a, const ResultItem &b) { return a.pred_avg < b.pred_avg;});
      }
   }
}

std::ostream &Result::info(std::ostream &os, std::string indent) const
{
   if (!m_predictions.empty())
   {
      std::uint64_t dtotal = 1;
      for(size_t d = 0; d < m_dims.size(); d++)
         dtotal *= m_dims[d];

      double test_fill_rate = 100. * m_predictions.size() / dtotal;

      os << indent << "Test data: " << m_predictions.size();

      os << " [";
      for(size_t d = 0; d < m_dims.size(); d++)
      {
         if(d == m_dims.size() - 1)
            os << m_dims[d];
         else
            os << m_dims[d] << " x ";
      }
      os << "]";

      os << " (" << test_fill_rate << "%)" << std::endl;

      if (classify)
      {
         double pos = 100. * (double)total_pos / (double)m_predictions.size();
         os << indent << "Binary classification threshold: " << threshold << std::endl;
         os << indent << "  " << pos << "% positives in test data" << std::endl;
      }
   }
   else
   {
      os << indent << "Test data: -" << std::endl;

      if (classify)
      {
         os << indent << "Binary classification threshold: " << threshold << std::endl;
         os << indent << "  " << "-" << "% positives in test data" << std::endl;
      }
   }

   return os;
}

bool Result::isEmpty() const
{
   return m_predictions.empty();
}
} // end namespace smurff
<|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 "libtorrent/pch.hpp"

#include <vector>
#include <iostream>
#include <cctype>
#include <iomanip>
#include <sstream>
#include <algorithm>

#include "libtorrent/config.hpp"
#include "libtorrent/gzip.hpp"

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

#include <boost/bind.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/tracker_manager.hpp"
#include "libtorrent/http_tracker_connection.hpp"
#include "libtorrent/http_connection.hpp"
#include "libtorrent/entry.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/io.hpp"
#include "libtorrent/socket.hpp"

using namespace libtorrent;
using boost::bind;

namespace libtorrent
{

	http_tracker_connection::http_tracker_connection(
		io_service& ios
		, connection_queue& cc
		, tracker_manager& man
		, tracker_request const& req
		, address bind_infc
		, boost::weak_ptr<request_callback> c
		, session_settings const& stn
		, proxy_settings const& ps
		, std::string const& auth)
		: tracker_connection(man, req, ios, bind_infc, c)
		, m_man(man)
		, m_settings(stn)
		, m_bind_iface(bind_infc)
		, m_ps(ps)
		, m_cc(cc)
		, m_ios(ios)
	{}

	void http_tracker_connection::start()
	{
		// TODO: authentication
		std::string url = tracker_req().url;

		if (tracker_req().kind == tracker_request::scrape_request)
		{
			// find and replace "announce" with "scrape"
			// in request

			std::size_t pos = url.find("announce");
			if (pos == std::string::npos)
			{
				fail(-1, ("scrape is not available on url: '"
					+ tracker_req().url +"'").c_str());
				return;
			}
			url.replace(pos, 8, "scrape");
		}

		// if request-string already contains
		// some parameters, append an ampersand instead
		// of a question mark
		size_t arguments_start = url.find('?');
		if (arguments_start != std::string::npos)
			url += "&";
		else
			url += "?";

		url += "info_hash=";
		url += escape_string(
			reinterpret_cast<const char*>(tracker_req().info_hash.begin()), 20);

		if (tracker_req().kind == tracker_request::announce_request)
		{
			url += "&peer_id=";
			url += escape_string(
				reinterpret_cast<const char*>(tracker_req().pid.begin()), 20);

			url += "&port=";
			url += boost::lexical_cast<std::string>(tracker_req().listen_port);

			url += "&uploaded=";
			url += boost::lexical_cast<std::string>(tracker_req().uploaded);

			url += "&downloaded=";
			url += boost::lexical_cast<std::string>(tracker_req().downloaded);

			url += "&left=";
			url += boost::lexical_cast<std::string>(tracker_req().left);

			if (tracker_req().event != tracker_request::none)
			{
				const char* event_string[] = {"completed", "started", "stopped"};
				url += "&event=";
				url += event_string[tracker_req().event - 1];
			}

			url += "&key=";
			std::stringstream key_string;
			key_string << std::hex << tracker_req().key;
			url += key_string.str();

			url += "&compact=1";

			url += "&numwant=";
			url += boost::lexical_cast<std::string>(
				(std::min)(tracker_req().num_want, 999));

			if (m_settings.announce_ip != address())
			{
				url += "&ip=";
				url += m_settings.announce_ip.to_string();
			}

#ifndef TORRENT_DISABLE_ENCRYPTION
			url += "&supportcrypto=1";
#endif
			url += "&ipv6=";
			url += tracker_req().ipv6;

			// extension that tells the tracker that
			// we don't need any peer_id's in the response
			url += "&no_peer_id=1";
		}

		m_tracker_connection.reset(new http_connection(m_ios, m_cc
			, boost::bind(&http_tracker_connection::on_response, self(), _1, _2, _3, _4)));

		int timeout = tracker_req().event==tracker_request::stopped
			?m_settings.stop_tracker_timeout
			:m_settings.tracker_completion_timeout;

		m_tracker_connection->get(url, seconds(timeout)
			, 1, &m_ps, 5, m_settings.user_agent, m_bind_iface);

		// the url + 100 estimated header size
		sent_bytes(url.size() + 100);

#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)

		boost::shared_ptr<request_callback> cb = requester();
		if (cb)
		{
			cb->debug_log("==> TRACKER_REQUEST [ url: " + url + " ]");
		}
#endif
	}

	void http_tracker_connection::close()
	{
		if (m_tracker_connection)
		{
			m_tracker_connection->close();
			m_tracker_connection.reset();
		}
		tracker_connection::close();
	}

	void http_tracker_connection::on_response(error_code const& ec
		, http_parser const& parser, char const* data, int size)
	{
		// keep this alive
		boost::intrusive_ptr<http_tracker_connection> me(this);

		if (ec && ec != asio::error::eof)
		{
			fail(-1, ec.message().c_str());
			return;
		}

		if (!parser.header_finished())
		{
			fail(-1, "premature end of file");
			return;
		}

		if (parser.status_code() != 200)
		{
			fail(parser.status_code(), parser.message().c_str());
			return;
		}

		if (ec && ec != asio::error::eof)
		{
			fail(parser.status_code(), ec.message().c_str());
			return;
		}

		received_bytes(size + parser.body_start());

		// handle tracker response
		entry e;
		e = bdecode(data, data + size);

		if (e.type() == entry::dictionary_t)
		{
			parse(parser.status_code(), e);
		}
		else
		{
			std::string error_str("invalid bencoding of tracker response: \"");
			for (char const* i = data, *end(data + size); i != end; ++i)
			{
				if (std::isprint(*i)) error_str += *i;
				else error_str += "0x" + boost::lexical_cast<std::string>((unsigned int)*i) + " ";
			}
			error_str += "\"";
			fail(parser.status_code(), error_str.c_str());
		}
		close();
	}

	bool http_tracker_connection::extract_peer_info(const entry& info, peer_entry& ret)
	{
		// extract peer id (if any)
		if (info.type() != entry::dictionary_t)
		{
			fail(-1, "invalid response from tracker (invalid peer entry)");
			return false;
		}
		entry const* i = info.find_key("peer id");
		if (i != 0)
		{
			if (i->type() != entry::string_t || i->string().length() != 20)
			{
				fail(-1, "invalid response from tracker (invalid peer id)");
				return false;
			}
			std::copy(i->string().begin(), i->string().end(), ret.pid.begin());
		}
		else
		{
			// if there's no peer_id, just initialize it to a bunch of zeroes
			std::fill_n(ret.pid.begin(), 20, 0);
		}

		// extract ip
		i = info.find_key("ip");
		if (i == 0 || i->type() != entry::string_t)
		{
			fail(-1, "invalid response from tracker");
			return false;
		}
		ret.ip = i->string();

		// extract port
		i = info.find_key("port");
		if (i == 0 || i->type() != entry::int_t)
		{
			fail(-1, "invalid response from tracker");
			return false;
		}
		ret.port = (unsigned short)i->integer();

		return true;
	}

	void http_tracker_connection::parse(int status_code, entry const& e)
	{
		boost::shared_ptr<request_callback> cb = requester();
		if (!cb) return;

		// parse the response
		entry const* failure = e.find_key("failure reason");
		if (failure && failure->type() == entry::string_t)
		{
			fail(status_code, failure->string().c_str());
			return;
		}

		entry const* warning = e.find_key("warning message");
		if (warning && warning->type() == entry::string_t)
		{
			cb->tracker_warning(tracker_req(), warning->string());
		}

		std::vector<peer_entry> peer_list;

		if (tracker_req().kind == tracker_request::scrape_request)
		{
			std::string ih = tracker_req().info_hash.to_string();

			entry const* files = e.find_key("files");
			if (files == 0 || files->type() != entry::dictionary_t)
			{
				fail(-1, "invalid or missing 'files' entry in scrape response");
				return;
			}

			entry const* scrape_data = files->find_key(ih);
			if (scrape_data == 0 || scrape_data->type() != entry::dictionary_t)
			{
				fail(-1, "missing or invalid info-hash entry in scrape response");
				return;
			}
			entry const* complete = scrape_data->find_key("complete");
			entry const* incomplete = scrape_data->find_key("incomplete");
			entry const* downloaded = scrape_data->find_key("downloaded");
			if (complete == 0 || incomplete == 0 || downloaded == 0
				|| complete->type() != entry::int_t
				|| incomplete->type() != entry::int_t
				|| downloaded->type() != entry::int_t)
			{
				fail(-1, "missing 'complete' or 'incomplete' entries in scrape response");
				return;
			}
			cb->tracker_scrape_response(tracker_req(), int(complete->integer())
				, int(incomplete->integer()), int(downloaded->integer()));
			return;
		}

		entry const* interval = e.find_key("interval");
		if (interval == 0 || interval->type() != entry::int_t)
		{
			fail(-1, "missing or invalid 'interval' entry in tracker response");
			return;
		}

		entry const* peers_ent = e.find_key("peers");
		if (peers_ent == 0)
		{
			fail(-1, "missing 'peers' entry in tracker response");
			return;
		}

		if (peers_ent->type() == entry::string_t)
		{
			std::string const& peers = peers_ent->string();
			for (std::string::const_iterator i = peers.begin();
				i != peers.end();)
			{
				if (std::distance(i, peers.end()) < 6) break;

				peer_entry p;
				p.pid.clear();
				p.ip = detail::read_v4_address(i).to_string();
				p.port = detail::read_uint16(i);
				peer_list.push_back(p);
			}
		}
		else if (peers_ent->type() == entry::list_t)
		{
			entry::list_type const& l = peers_ent->list();
			for(entry::list_type::const_iterator i = l.begin(); i != l.end(); ++i)
			{
				peer_entry p;
				if (!extract_peer_info(*i, p)) return;
				peer_list.push_back(p);
			}
		}
		else
		{
			fail(-1, "invalid 'peers' entry in tracker response");
			return;
		}

		entry const* ipv6_peers = e.find_key("peers6");
		if (ipv6_peers && ipv6_peers->type() == entry::string_t)
		{
			std::string const& peers = ipv6_peers->string();
			for (std::string::const_iterator i = peers.begin();
				i != peers.end();)
			{
				if (std::distance(i, peers.end()) < 18) break;

				peer_entry p;
				p.pid.clear();
				p.ip = detail::read_v6_address(i).to_string();
				p.port = detail::read_uint16(i);
				peer_list.push_back(p);
			}
		}

		// look for optional scrape info
		int complete = -1;
		int incomplete = -1;
		address external_ip;

		entry const* ip_ent = e.find_key("external ip");
		if (ip_ent && ip_ent->type() == entry::string_t)
		{
			std::string const& ip = ip_ent->string();
			char const* p = &ip[0];
			if (ip.size() == address_v4::bytes_type::static_size)
				external_ip = detail::read_v4_address(p);
			else if (ip.size() == address_v6::bytes_type::static_size)
				external_ip = detail::read_v6_address(p);
		}

		entry const* complete_ent = e.find_key("complete");
		if (complete_ent && complete_ent->type() == entry::int_t)
			complete = int(complete_ent->integer());

		entry const* incomplete_ent = e.find_key("incomplete");
		if (incomplete_ent && incomplete_ent->type() == entry::int_t)
			incomplete = int(incomplete_ent->integer());

		cb->tracker_response(tracker_req(), peer_list, interval->integer(), complete
			, incomplete, external_ip);
	}

}

<commit_msg>fixed bug in error alert from http_tracker_connection<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 "libtorrent/pch.hpp"

#include <vector>
#include <iostream>
#include <cctype>
#include <iomanip>
#include <sstream>
#include <algorithm>

#include "libtorrent/config.hpp"
#include "libtorrent/gzip.hpp"

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

#include <boost/bind.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/tracker_manager.hpp"
#include "libtorrent/http_tracker_connection.hpp"
#include "libtorrent/http_connection.hpp"
#include "libtorrent/entry.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/io.hpp"
#include "libtorrent/socket.hpp"

using namespace libtorrent;
using boost::bind;

namespace libtorrent
{

	http_tracker_connection::http_tracker_connection(
		io_service& ios
		, connection_queue& cc
		, tracker_manager& man
		, tracker_request const& req
		, address bind_infc
		, boost::weak_ptr<request_callback> c
		, session_settings const& stn
		, proxy_settings const& ps
		, std::string const& auth)
		: tracker_connection(man, req, ios, bind_infc, c)
		, m_man(man)
		, m_settings(stn)
		, m_bind_iface(bind_infc)
		, m_ps(ps)
		, m_cc(cc)
		, m_ios(ios)
	{}

	void http_tracker_connection::start()
	{
		// TODO: authentication
		std::string url = tracker_req().url;

		if (tracker_req().kind == tracker_request::scrape_request)
		{
			// find and replace "announce" with "scrape"
			// in request

			std::size_t pos = url.find("announce");
			if (pos == std::string::npos)
			{
				fail(-1, ("scrape is not available on url: '"
					+ tracker_req().url +"'").c_str());
				return;
			}
			url.replace(pos, 8, "scrape");
		}

		// if request-string already contains
		// some parameters, append an ampersand instead
		// of a question mark
		size_t arguments_start = url.find('?');
		if (arguments_start != std::string::npos)
			url += "&";
		else
			url += "?";

		url += "info_hash=";
		url += escape_string(
			reinterpret_cast<const char*>(tracker_req().info_hash.begin()), 20);

		if (tracker_req().kind == tracker_request::announce_request)
		{
			url += "&peer_id=";
			url += escape_string(
				reinterpret_cast<const char*>(tracker_req().pid.begin()), 20);

			url += "&port=";
			url += boost::lexical_cast<std::string>(tracker_req().listen_port);

			url += "&uploaded=";
			url += boost::lexical_cast<std::string>(tracker_req().uploaded);

			url += "&downloaded=";
			url += boost::lexical_cast<std::string>(tracker_req().downloaded);

			url += "&left=";
			url += boost::lexical_cast<std::string>(tracker_req().left);

			if (tracker_req().event != tracker_request::none)
			{
				const char* event_string[] = {"completed", "started", "stopped"};
				url += "&event=";
				url += event_string[tracker_req().event - 1];
			}

			url += "&key=";
			std::stringstream key_string;
			key_string << std::hex << tracker_req().key;
			url += key_string.str();

			url += "&compact=1";

			url += "&numwant=";
			url += boost::lexical_cast<std::string>(
				(std::min)(tracker_req().num_want, 999));

			if (m_settings.announce_ip != address())
			{
				url += "&ip=";
				url += m_settings.announce_ip.to_string();
			}

#ifndef TORRENT_DISABLE_ENCRYPTION
			url += "&supportcrypto=1";
#endif
			url += "&ipv6=";
			url += tracker_req().ipv6;

			// extension that tells the tracker that
			// we don't need any peer_id's in the response
			url += "&no_peer_id=1";
		}

		m_tracker_connection.reset(new http_connection(m_ios, m_cc
			, boost::bind(&http_tracker_connection::on_response, self(), _1, _2, _3, _4)));

		int timeout = tracker_req().event==tracker_request::stopped
			?m_settings.stop_tracker_timeout
			:m_settings.tracker_completion_timeout;

		m_tracker_connection->get(url, seconds(timeout)
			, 1, &m_ps, 5, m_settings.user_agent, m_bind_iface);

		// the url + 100 estimated header size
		sent_bytes(url.size() + 100);

#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)

		boost::shared_ptr<request_callback> cb = requester();
		if (cb)
		{
			cb->debug_log("==> TRACKER_REQUEST [ url: " + url + " ]");
		}
#endif
	}

	void http_tracker_connection::close()
	{
		if (m_tracker_connection)
		{
			m_tracker_connection->close();
			m_tracker_connection.reset();
		}
		tracker_connection::close();
	}

	void http_tracker_connection::on_response(error_code const& ec
		, http_parser const& parser, char const* data, int size)
	{
		// keep this alive
		boost::intrusive_ptr<http_tracker_connection> me(this);

		if (ec && ec != asio::error::eof)
		{
			fail(-1, ec.message().c_str());
			return;
		}

		if (!parser.header_finished())
		{
			fail(-1, "premature end of file");
			return;
		}

		if (parser.status_code() != 200)
		{
			fail(parser.status_code(), parser.message().c_str());
			return;
		}

		if (ec && ec != asio::error::eof)
		{
			fail(parser.status_code(), ec.message().c_str());
			return;
		}

		received_bytes(size + parser.body_start());

		// handle tracker response
		entry e;
		e = bdecode(data, data + size);

		if (e.type() == entry::dictionary_t)
		{
			parse(parser.status_code(), e);
		}
		else
		{
			std::string error_str("invalid bencoding of tracker response: \"");
			for (char const* i = data, *end(data + size); i != end; ++i)
			{
				if (*i >= ' ' && *i <= '~') error_str += *i;
				else error_str += "0x" + boost::lexical_cast<std::string>((unsigned int)*i) + " ";
			}
			error_str += "\"";
			fail(parser.status_code(), error_str.c_str());
		}
		close();
	}

	bool http_tracker_connection::extract_peer_info(const entry& info, peer_entry& ret)
	{
		// extract peer id (if any)
		if (info.type() != entry::dictionary_t)
		{
			fail(-1, "invalid response from tracker (invalid peer entry)");
			return false;
		}
		entry const* i = info.find_key("peer id");
		if (i != 0)
		{
			if (i->type() != entry::string_t || i->string().length() != 20)
			{
				fail(-1, "invalid response from tracker (invalid peer id)");
				return false;
			}
			std::copy(i->string().begin(), i->string().end(), ret.pid.begin());
		}
		else
		{
			// if there's no peer_id, just initialize it to a bunch of zeroes
			std::fill_n(ret.pid.begin(), 20, 0);
		}

		// extract ip
		i = info.find_key("ip");
		if (i == 0 || i->type() != entry::string_t)
		{
			fail(-1, "invalid response from tracker");
			return false;
		}
		ret.ip = i->string();

		// extract port
		i = info.find_key("port");
		if (i == 0 || i->type() != entry::int_t)
		{
			fail(-1, "invalid response from tracker");
			return false;
		}
		ret.port = (unsigned short)i->integer();

		return true;
	}

	void http_tracker_connection::parse(int status_code, entry const& e)
	{
		boost::shared_ptr<request_callback> cb = requester();
		if (!cb) return;

		// parse the response
		entry const* failure = e.find_key("failure reason");
		if (failure && failure->type() == entry::string_t)
		{
			fail(status_code, failure->string().c_str());
			return;
		}

		entry const* warning = e.find_key("warning message");
		if (warning && warning->type() == entry::string_t)
		{
			cb->tracker_warning(tracker_req(), warning->string());
		}

		std::vector<peer_entry> peer_list;

		if (tracker_req().kind == tracker_request::scrape_request)
		{
			std::string ih = tracker_req().info_hash.to_string();

			entry const* files = e.find_key("files");
			if (files == 0 || files->type() != entry::dictionary_t)
			{
				fail(-1, "invalid or missing 'files' entry in scrape response");
				return;
			}

			entry const* scrape_data = files->find_key(ih);
			if (scrape_data == 0 || scrape_data->type() != entry::dictionary_t)
			{
				fail(-1, "missing or invalid info-hash entry in scrape response");
				return;
			}
			entry const* complete = scrape_data->find_key("complete");
			entry const* incomplete = scrape_data->find_key("incomplete");
			entry const* downloaded = scrape_data->find_key("downloaded");
			if (complete == 0 || incomplete == 0 || downloaded == 0
				|| complete->type() != entry::int_t
				|| incomplete->type() != entry::int_t
				|| downloaded->type() != entry::int_t)
			{
				fail(-1, "missing 'complete' or 'incomplete' entries in scrape response");
				return;
			}
			cb->tracker_scrape_response(tracker_req(), int(complete->integer())
				, int(incomplete->integer()), int(downloaded->integer()));
			return;
		}

		entry const* interval = e.find_key("interval");
		if (interval == 0 || interval->type() != entry::int_t)
		{
			fail(-1, "missing or invalid 'interval' entry in tracker response");
			return;
		}

		entry const* peers_ent = e.find_key("peers");
		if (peers_ent == 0)
		{
			fail(-1, "missing 'peers' entry in tracker response");
			return;
		}

		if (peers_ent->type() == entry::string_t)
		{
			std::string const& peers = peers_ent->string();
			for (std::string::const_iterator i = peers.begin();
				i != peers.end();)
			{
				if (std::distance(i, peers.end()) < 6) break;

				peer_entry p;
				p.pid.clear();
				p.ip = detail::read_v4_address(i).to_string();
				p.port = detail::read_uint16(i);
				peer_list.push_back(p);
			}
		}
		else if (peers_ent->type() == entry::list_t)
		{
			entry::list_type const& l = peers_ent->list();
			for(entry::list_type::const_iterator i = l.begin(); i != l.end(); ++i)
			{
				peer_entry p;
				if (!extract_peer_info(*i, p)) return;
				peer_list.push_back(p);
			}
		}
		else
		{
			fail(-1, "invalid 'peers' entry in tracker response");
			return;
		}

		entry const* ipv6_peers = e.find_key("peers6");
		if (ipv6_peers && ipv6_peers->type() == entry::string_t)
		{
			std::string const& peers = ipv6_peers->string();
			for (std::string::const_iterator i = peers.begin();
				i != peers.end();)
			{
				if (std::distance(i, peers.end()) < 18) break;

				peer_entry p;
				p.pid.clear();
				p.ip = detail::read_v6_address(i).to_string();
				p.port = detail::read_uint16(i);
				peer_list.push_back(p);
			}
		}

		// look for optional scrape info
		int complete = -1;
		int incomplete = -1;
		address external_ip;

		entry const* ip_ent = e.find_key("external ip");
		if (ip_ent && ip_ent->type() == entry::string_t)
		{
			std::string const& ip = ip_ent->string();
			char const* p = &ip[0];
			if (ip.size() == address_v4::bytes_type::static_size)
				external_ip = detail::read_v4_address(p);
			else if (ip.size() == address_v6::bytes_type::static_size)
				external_ip = detail::read_v6_address(p);
		}

		entry const* complete_ent = e.find_key("complete");
		if (complete_ent && complete_ent->type() == entry::int_t)
			complete = int(complete_ent->integer());

		entry const* incomplete_ent = e.find_key("incomplete");
		if (incomplete_ent && incomplete_ent->type() == entry::int_t)
			incomplete = int(incomplete_ent->integer());

		cb->tracker_response(tracker_req(), peer_list, interval->integer(), complete
			, incomplete, external_ip);
	}

}

<|endoftext|>