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

#include "hwy/aligned_allocator.h"

#include <stddef.h>

#include <array>
#include <new>
#include <random>
#include <vector>

#include "gtest/gtest.h"

namespace {

// Sample object that keeps track on an external counter of how many times was
// the explicit constructor and destructor called.
template <size_t N>
class SampleObject {
 public:
  SampleObject() { data_[0] = 'a'; }
  explicit SampleObject(int* counter) : counter_(counter) {
    if (counter) (*counter)++;
    data_[0] = 'b';
  }

  ~SampleObject() {
    if (counter_) (*counter_)--;
  }

  static_assert(N > sizeof(int*), "SampleObject size too small.");
  int* counter_ = nullptr;
  char data_[N - sizeof(int*)];
};

class FakeAllocator {
 public:
  // static AllocPtr and FreePtr member to be used with the alligned
  // allocator. These functions calls the private non-static members.
  static void* StaticAlloc(void* opaque, size_t bytes) {
    return reinterpret_cast<FakeAllocator*>(opaque)->Alloc(bytes);
  }
  static void StaticFree(void* opaque, void* memory) {
    return reinterpret_cast<FakeAllocator*>(opaque)->Free(memory);
  }

  // Returns the number of pending allocations to be freed.
  size_t PendingAllocs() { return allocs_.size(); }

 private:
  void* Alloc(size_t bytes) {
    void* ret = malloc(bytes);
    allocs_.insert(ret);
    return ret;
  }
  void Free(void* memory) {
    if (!memory) return;
    EXPECT_NE(allocs_.end(), allocs_.find(memory));
    free(memory);
    allocs_.erase(memory);
  }

  std::set<void*> allocs_;
};

}  // namespace

namespace hwy {

class AlignedAllocatorTest : public testing::Test {};

TEST(AlignedAllocatorTest, FreeNullptr) {
  // Calling free with a nullptr is always ok.
  FreeAlignedBytes(/*aligned_pointer=*/nullptr, /*free_ptr=*/nullptr,
                   /*opaque_ptr=*/nullptr);
}

TEST(AlignedAllocatorTest, Log2) {
  EXPECT_EQ(0u, detail::ShiftCount(1));
  EXPECT_EQ(1u, detail::ShiftCount(2));
  EXPECT_EQ(3u, detail::ShiftCount(8));
}

// Allocator returns null when it detects overflow of items * sizeof(T).
TEST(AlignedAllocatorTest, Overflow) {
  constexpr size_t max = ~size_t(0);
  constexpr size_t msb = (max >> 1) + 1;
  using Size5 = std::array<uint8_t, 5>;
  using Size10 = std::array<uint8_t, 10>;
  EXPECT_EQ(nullptr,
            detail::AllocateAlignedItems<uint32_t>(max / 2, nullptr, nullptr));
  EXPECT_EQ(nullptr,
            detail::AllocateAlignedItems<uint32_t>(max / 3, nullptr, nullptr));
  EXPECT_EQ(nullptr,
            detail::AllocateAlignedItems<Size5>(max / 4, nullptr, nullptr));
  EXPECT_EQ(nullptr,
            detail::AllocateAlignedItems<uint16_t>(msb, nullptr, nullptr));
  EXPECT_EQ(nullptr,
            detail::AllocateAlignedItems<double>(msb + 1, nullptr, nullptr));
  EXPECT_EQ(nullptr,
            detail::AllocateAlignedItems<Size10>(msb / 4, nullptr, nullptr));
}

TEST(AlignedAllocatorTest, AllocDefaultPointers) {
  const size_t kSize = 7777;
  void* ptr = AllocateAlignedBytes(kSize, /*alloc_ptr=*/nullptr,
                                   /*opaque_ptr=*/nullptr);
  ASSERT_NE(nullptr, ptr);
  // Make sure the pointer is actually aligned.
  EXPECT_EQ(0U, reinterpret_cast<uintptr_t>(ptr) % HWY_ALIGNMENT);
  char* p = static_cast<char*>(ptr);
  size_t ret = 0;
  for (size_t i = 0; i < kSize; i++) {
    // Performs a computation using p[] to prevent it being optimized away.
    p[i] = static_cast<char>(i & 0x7F);
    if (i) ret += static_cast<size_t>(p[i] * p[i - 1]);
  }
  EXPECT_NE(0U, ret);
  FreeAlignedBytes(ptr, /*free_ptr=*/nullptr, /*opaque_ptr=*/nullptr);
}

TEST(AlignedAllocatorTest, EmptyAlignedUniquePtr) {
  AlignedUniquePtr<SampleObject<32>> ptr(nullptr, AlignedDeleter());
  AlignedUniquePtr<SampleObject<32>[]> arr(nullptr, AlignedDeleter());
}

TEST(AlignedAllocatorTest, EmptyAlignedFreeUniquePtr) {
  AlignedFreeUniquePtr<SampleObject<32>> ptr(nullptr, AlignedFreer());
  AlignedFreeUniquePtr<SampleObject<32>[]> arr(nullptr, AlignedFreer());
}

TEST(AlignedAllocatorTest, CustomAlloc) {
  FakeAllocator fake_alloc;

  const size_t kSize = 7777;
  void* ptr =
      AllocateAlignedBytes(kSize, &FakeAllocator::StaticAlloc, &fake_alloc);
  ASSERT_NE(nullptr, ptr);
  // We should have only requested one alloc from the allocator.
  EXPECT_EQ(1U, fake_alloc.PendingAllocs());
  // Make sure the pointer is actually aligned.
  EXPECT_EQ(0U, reinterpret_cast<uintptr_t>(ptr) % HWY_ALIGNMENT);
  FreeAlignedBytes(ptr, &FakeAllocator::StaticFree, &fake_alloc);
  EXPECT_EQ(0U, fake_alloc.PendingAllocs());
}

TEST(AlignedAllocatorTest, MakeUniqueAlignedDefaultConstructor) {
  {
    auto ptr = MakeUniqueAligned<SampleObject<24>>();
    // Default constructor sets the data_[0] to 'a'.
    EXPECT_EQ('a', ptr->data_[0]);
    EXPECT_EQ(nullptr, ptr->counter_);
  }
}

TEST(AlignedAllocatorTest, MakeUniqueAligned) {
  int counter = 0;
  {
    // Creates the object, initializes it with the explicit constructor and
    // returns an unique_ptr to it.
    auto ptr = MakeUniqueAligned<SampleObject<24>>(&counter);
    EXPECT_EQ(1, counter);
    // Custom constructor sets the data_[0] to 'b'.
    EXPECT_EQ('b', ptr->data_[0]);
  }
  EXPECT_EQ(0, counter);
}

TEST(AlignedAllocatorTest, MakeUniqueAlignedArray) {
  int counter = 0;
  {
    // Creates the array of objects and initializes them with the explicit
    // constructor.
    auto arr = MakeUniqueAlignedArray<SampleObject<24>>(7, &counter);
    EXPECT_EQ(7, counter);
    for (size_t i = 0; i < 7; i++) {
      // Custom constructor sets the data_[0] to 'b'.
      EXPECT_EQ('b', arr[i].data_[0]) << "Where i = " << i;
    }
  }
  EXPECT_EQ(0, counter);
}

TEST(AlignedAllocatorTest, AllocSingleInt) {
  auto ptr = AllocateAligned<uint32_t>(1);
  ASSERT_NE(nullptr, ptr.get());
  EXPECT_EQ(0U, reinterpret_cast<uintptr_t>(ptr.get()) % HWY_ALIGNMENT);
  // Force delete of the unique_ptr now to check that it doesn't crash.
  ptr.reset(nullptr);
  EXPECT_EQ(nullptr, ptr.get());
}

TEST(AlignedAllocatorTest, AllocMultipleInt) {
  const size_t kSize = 7777;
  auto ptr = AllocateAligned<uint32_t>(kSize);
  ASSERT_NE(nullptr, ptr.get());
  EXPECT_EQ(0U, reinterpret_cast<uintptr_t>(ptr.get()) % HWY_ALIGNMENT);
  // ptr[i] is actually (*ptr.get())[i] which will use the operator[] of the
  // underlying type chosen by AllocateAligned() for the std::unique_ptr.
  EXPECT_EQ(&(ptr[0]) + 1, &(ptr[1]));

  size_t ret = 0;
  for (size_t i = 0; i < kSize; i++) {
    // Performs a computation using ptr[] to prevent it being optimized away.
    ptr[i] = static_cast<uint32_t>(i);
    if (i) ret += ptr[i] * ptr[i - 1];
  }
  EXPECT_NE(0U, ret);
}

TEST(AlignedAllocatorTest, AllocateAlignedObjectWithoutDestructor) {
  int counter = 0;
  {
    // This doesn't call the constructor.
    auto obj = AllocateAligned<SampleObject<24>>(1);
    obj[0].counter_ = &counter;
  }
  // Destroying the unique_ptr shouldn't have called the destructor of the
  // SampleObject<24>.
  EXPECT_EQ(0, counter);
}

TEST(AlignedAllocatorTest, MakeUniqueAlignedArrayWithCustomAlloc) {
  FakeAllocator fake_alloc;
  int counter = 0;
  {
    // Creates the array of objects and initializes them with the explicit
    // constructor.
    auto arr = MakeUniqueAlignedArrayWithAlloc<SampleObject<24>>(
        7, FakeAllocator::StaticAlloc, FakeAllocator::StaticFree, &fake_alloc,
        &counter);
    ASSERT_NE(nullptr, arr.get());
    // An array should still only call a single allocation.
    EXPECT_EQ(1u, fake_alloc.PendingAllocs());
    EXPECT_EQ(7, counter);
    for (size_t i = 0; i < 7; i++) {
      // Custom constructor sets the data_[0] to 'b'.
      EXPECT_EQ('b', arr[i].data_[0]) << "Where i = " << i;
    }
  }
  EXPECT_EQ(0, counter);
  EXPECT_EQ(0u, fake_alloc.PendingAllocs());
}

TEST(AlignedAllocatorTest, DefaultInit) {
  // The test is whether this compiles. Default-init is useful for output params
  // and per-thread storage.
  std::vector<AlignedUniquePtr<int[]>> ptrs;
  std::vector<AlignedFreeUniquePtr<double[]>> free_ptrs;
  ptrs.resize(128);
  free_ptrs.resize(128);
  // The following is to prevent elision of the pointers.
  std::mt19937 rng(129);  // Emscripten lacks random_device.
  std::uniform_int_distribution<size_t> dist(0, 127);
  ptrs[dist(rng)] = MakeUniqueAlignedArray<int>(123);
  free_ptrs[dist(rng)] = AllocateAligned<double>(456);
  // "Use" pointer without resorting to printf. 0 == 0. Can't shift by 64.
  const auto addr1 = reinterpret_cast<uintptr_t>(ptrs[dist(rng)].get());
  const auto addr2 = reinterpret_cast<uintptr_t>(free_ptrs[dist(rng)].get());
  constexpr size_t kBits = sizeof(uintptr_t) * 8;
  EXPECT_EQ((addr1 >> (kBits - 1)) >> (kBits - 1),
            (addr2 >> (kBits - 1)) >> (kBits - 1));
}

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

#include "hwy/aligned_allocator.h"

#include <stddef.h>

#include <array>
#include <new>
#include <random>
#include <vector>

#include "gtest/gtest.h"

namespace {

// Sample object that keeps track on an external counter of how many times was
// the explicit constructor and destructor called.
template <size_t N>
class SampleObject {
 public:
  SampleObject() { data_[0] = 'a'; }
  explicit SampleObject(int* counter) : counter_(counter) {
    if (counter) (*counter)++;
    data_[0] = 'b';
  }

  ~SampleObject() {
    if (counter_) (*counter_)--;
  }

  static_assert(N > sizeof(int*), "SampleObject size too small.");
  int* counter_ = nullptr;
  char data_[N - sizeof(int*)];
};

class FakeAllocator {
 public:
  // static AllocPtr and FreePtr member to be used with the alligned
  // allocator. These functions calls the private non-static members.
  static void* StaticAlloc(void* opaque, size_t bytes) {
    return reinterpret_cast<FakeAllocator*>(opaque)->Alloc(bytes);
  }
  static void StaticFree(void* opaque, void* memory) {
    return reinterpret_cast<FakeAllocator*>(opaque)->Free(memory);
  }

  // Returns the number of pending allocations to be freed.
  size_t PendingAllocs() { return allocs_.size(); }

 private:
  void* Alloc(size_t bytes) {
    void* ret = malloc(bytes);
    allocs_.insert(ret);
    return ret;
  }
  void Free(void* memory) {
    if (!memory) return;
    EXPECT_NE(allocs_.end(), allocs_.find(memory));
    allocs_.erase(memory);
    free(memory);
  }

  std::set<void*> allocs_;
};

}  // namespace

namespace hwy {

class AlignedAllocatorTest : public testing::Test {};

TEST(AlignedAllocatorTest, FreeNullptr) {
  // Calling free with a nullptr is always ok.
  FreeAlignedBytes(/*aligned_pointer=*/nullptr, /*free_ptr=*/nullptr,
                   /*opaque_ptr=*/nullptr);
}

TEST(AlignedAllocatorTest, Log2) {
  EXPECT_EQ(0u, detail::ShiftCount(1));
  EXPECT_EQ(1u, detail::ShiftCount(2));
  EXPECT_EQ(3u, detail::ShiftCount(8));
}

// Allocator returns null when it detects overflow of items * sizeof(T).
TEST(AlignedAllocatorTest, Overflow) {
  constexpr size_t max = ~size_t(0);
  constexpr size_t msb = (max >> 1) + 1;
  using Size5 = std::array<uint8_t, 5>;
  using Size10 = std::array<uint8_t, 10>;
  EXPECT_EQ(nullptr,
            detail::AllocateAlignedItems<uint32_t>(max / 2, nullptr, nullptr));
  EXPECT_EQ(nullptr,
            detail::AllocateAlignedItems<uint32_t>(max / 3, nullptr, nullptr));
  EXPECT_EQ(nullptr,
            detail::AllocateAlignedItems<Size5>(max / 4, nullptr, nullptr));
  EXPECT_EQ(nullptr,
            detail::AllocateAlignedItems<uint16_t>(msb, nullptr, nullptr));
  EXPECT_EQ(nullptr,
            detail::AllocateAlignedItems<double>(msb + 1, nullptr, nullptr));
  EXPECT_EQ(nullptr,
            detail::AllocateAlignedItems<Size10>(msb / 4, nullptr, nullptr));
}

TEST(AlignedAllocatorTest, AllocDefaultPointers) {
  const size_t kSize = 7777;
  void* ptr = AllocateAlignedBytes(kSize, /*alloc_ptr=*/nullptr,
                                   /*opaque_ptr=*/nullptr);
  ASSERT_NE(nullptr, ptr);
  // Make sure the pointer is actually aligned.
  EXPECT_EQ(0U, reinterpret_cast<uintptr_t>(ptr) % HWY_ALIGNMENT);
  char* p = static_cast<char*>(ptr);
  size_t ret = 0;
  for (size_t i = 0; i < kSize; i++) {
    // Performs a computation using p[] to prevent it being optimized away.
    p[i] = static_cast<char>(i & 0x7F);
    if (i) ret += static_cast<size_t>(p[i] * p[i - 1]);
  }
  EXPECT_NE(0U, ret);
  FreeAlignedBytes(ptr, /*free_ptr=*/nullptr, /*opaque_ptr=*/nullptr);
}

TEST(AlignedAllocatorTest, EmptyAlignedUniquePtr) {
  AlignedUniquePtr<SampleObject<32>> ptr(nullptr, AlignedDeleter());
  AlignedUniquePtr<SampleObject<32>[]> arr(nullptr, AlignedDeleter());
}

TEST(AlignedAllocatorTest, EmptyAlignedFreeUniquePtr) {
  AlignedFreeUniquePtr<SampleObject<32>> ptr(nullptr, AlignedFreer());
  AlignedFreeUniquePtr<SampleObject<32>[]> arr(nullptr, AlignedFreer());
}

TEST(AlignedAllocatorTest, CustomAlloc) {
  FakeAllocator fake_alloc;

  const size_t kSize = 7777;
  void* ptr =
      AllocateAlignedBytes(kSize, &FakeAllocator::StaticAlloc, &fake_alloc);
  ASSERT_NE(nullptr, ptr);
  // We should have only requested one alloc from the allocator.
  EXPECT_EQ(1U, fake_alloc.PendingAllocs());
  // Make sure the pointer is actually aligned.
  EXPECT_EQ(0U, reinterpret_cast<uintptr_t>(ptr) % HWY_ALIGNMENT);
  FreeAlignedBytes(ptr, &FakeAllocator::StaticFree, &fake_alloc);
  EXPECT_EQ(0U, fake_alloc.PendingAllocs());
}

TEST(AlignedAllocatorTest, MakeUniqueAlignedDefaultConstructor) {
  {
    auto ptr = MakeUniqueAligned<SampleObject<24>>();
    // Default constructor sets the data_[0] to 'a'.
    EXPECT_EQ('a', ptr->data_[0]);
    EXPECT_EQ(nullptr, ptr->counter_);
  }
}

TEST(AlignedAllocatorTest, MakeUniqueAligned) {
  int counter = 0;
  {
    // Creates the object, initializes it with the explicit constructor and
    // returns an unique_ptr to it.
    auto ptr = MakeUniqueAligned<SampleObject<24>>(&counter);
    EXPECT_EQ(1, counter);
    // Custom constructor sets the data_[0] to 'b'.
    EXPECT_EQ('b', ptr->data_[0]);
  }
  EXPECT_EQ(0, counter);
}

TEST(AlignedAllocatorTest, MakeUniqueAlignedArray) {
  int counter = 0;
  {
    // Creates the array of objects and initializes them with the explicit
    // constructor.
    auto arr = MakeUniqueAlignedArray<SampleObject<24>>(7, &counter);
    EXPECT_EQ(7, counter);
    for (size_t i = 0; i < 7; i++) {
      // Custom constructor sets the data_[0] to 'b'.
      EXPECT_EQ('b', arr[i].data_[0]) << "Where i = " << i;
    }
  }
  EXPECT_EQ(0, counter);
}

TEST(AlignedAllocatorTest, AllocSingleInt) {
  auto ptr = AllocateAligned<uint32_t>(1);
  ASSERT_NE(nullptr, ptr.get());
  EXPECT_EQ(0U, reinterpret_cast<uintptr_t>(ptr.get()) % HWY_ALIGNMENT);
  // Force delete of the unique_ptr now to check that it doesn't crash.
  ptr.reset(nullptr);
  EXPECT_EQ(nullptr, ptr.get());
}

TEST(AlignedAllocatorTest, AllocMultipleInt) {
  const size_t kSize = 7777;
  auto ptr = AllocateAligned<uint32_t>(kSize);
  ASSERT_NE(nullptr, ptr.get());
  EXPECT_EQ(0U, reinterpret_cast<uintptr_t>(ptr.get()) % HWY_ALIGNMENT);
  // ptr[i] is actually (*ptr.get())[i] which will use the operator[] of the
  // underlying type chosen by AllocateAligned() for the std::unique_ptr.
  EXPECT_EQ(&(ptr[0]) + 1, &(ptr[1]));

  size_t ret = 0;
  for (size_t i = 0; i < kSize; i++) {
    // Performs a computation using ptr[] to prevent it being optimized away.
    ptr[i] = static_cast<uint32_t>(i);
    if (i) ret += ptr[i] * ptr[i - 1];
  }
  EXPECT_NE(0U, ret);
}

TEST(AlignedAllocatorTest, AllocateAlignedObjectWithoutDestructor) {
  int counter = 0;
  {
    // This doesn't call the constructor.
    auto obj = AllocateAligned<SampleObject<24>>(1);
    obj[0].counter_ = &counter;
  }
  // Destroying the unique_ptr shouldn't have called the destructor of the
  // SampleObject<24>.
  EXPECT_EQ(0, counter);
}

TEST(AlignedAllocatorTest, MakeUniqueAlignedArrayWithCustomAlloc) {
  FakeAllocator fake_alloc;
  int counter = 0;
  {
    // Creates the array of objects and initializes them with the explicit
    // constructor.
    auto arr = MakeUniqueAlignedArrayWithAlloc<SampleObject<24>>(
        7, FakeAllocator::StaticAlloc, FakeAllocator::StaticFree, &fake_alloc,
        &counter);
    ASSERT_NE(nullptr, arr.get());
    // An array should still only call a single allocation.
    EXPECT_EQ(1u, fake_alloc.PendingAllocs());
    EXPECT_EQ(7, counter);
    for (size_t i = 0; i < 7; i++) {
      // Custom constructor sets the data_[0] to 'b'.
      EXPECT_EQ('b', arr[i].data_[0]) << "Where i = " << i;
    }
  }
  EXPECT_EQ(0, counter);
  EXPECT_EQ(0u, fake_alloc.PendingAllocs());
}

TEST(AlignedAllocatorTest, DefaultInit) {
  // The test is whether this compiles. Default-init is useful for output params
  // and per-thread storage.
  std::vector<AlignedUniquePtr<int[]>> ptrs;
  std::vector<AlignedFreeUniquePtr<double[]>> free_ptrs;
  ptrs.resize(128);
  free_ptrs.resize(128);
  // The following is to prevent elision of the pointers.
  std::mt19937 rng(129);  // Emscripten lacks random_device.
  std::uniform_int_distribution<size_t> dist(0, 127);
  ptrs[dist(rng)] = MakeUniqueAlignedArray<int>(123);
  free_ptrs[dist(rng)] = AllocateAligned<double>(456);
  // "Use" pointer without resorting to printf. 0 == 0. Can't shift by 64.
  const auto addr1 = reinterpret_cast<uintptr_t>(ptrs[dist(rng)].get());
  const auto addr2 = reinterpret_cast<uintptr_t>(free_ptrs[dist(rng)].get());
  constexpr size_t kBits = sizeof(uintptr_t) * 8;
  EXPECT_EQ((addr1 >> (kBits - 1)) >> (kBits - 1),
            (addr2 >> (kBits - 1)) >> (kBits - 1));
}

}  // namespace hwy
<|endoftext|>


<commit_before>/*
 * AtomsReader.cpp
 *****************************************************************************
 * Copyright (C) 2014 - VideoLAN authors
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program 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 program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/
#include "AtomsReader.hpp"
#include "mpd/Representation.h"
#include "mpd/MPD.h"

using namespace dash::mp4;
using namespace dash::mpd;

AtomsReader::AtomsReader(vlc_object_t *object_)
{
    object = object_;
    rootbox = NULL;
}

AtomsReader::~AtomsReader()
{
    while(rootbox && rootbox->p_first)
    {
        MP4_Box_t *p_next = rootbox->p_first->p_next;
        MP4_BoxFree( (stream_t *)object, rootbox->p_first );
        rootbox->p_first = p_next;
    }
    delete rootbox;
}

bool AtomsReader::parseBlock(void *buffer, size_t size, BaseRepresentation *rep)
{
    if(!rep)
        return false;

    stream_t *stream = stream_MemoryNew( object, (uint8_t *)buffer, size, true);
    if (stream)
    {
        rootbox = new MP4_Box_t;
        if(!rootbox)
        {
            stream_Delete(stream);
            return false;
        }
        memset(rootbox, 0, sizeof(*rootbox));
        rootbox->i_type = ATOM_root;
        rootbox->i_size = size;
        if ( MP4_ReadBoxContainerChildren( stream, rootbox, 0 ) == 1 )
        {
#ifndef NDEBUG
            MP4_BoxDumpStructure(stream, rootbox);
#endif
            MP4_Box_t *sidxbox = MP4_BoxGet(rootbox, "sidx");
            if (sidxbox)
            {
                Representation::SplitPoint point;
                std::vector<Representation::SplitPoint> splitlist;
                MP4_Box_data_sidx_t *sidx = sidxbox->data.p_sidx;
                point.offset = sidx->i_first_offset;
                point.time = 0;
                for(uint16_t i=0; i<sidx->i_reference_count; i++)
                {
                    splitlist.push_back(point);
                    point.offset += sidx->p_items[i].i_referenced_size;
                    point.time += sidx->p_items[i].i_subsegment_duration;
                }
                rep->SplitUsingIndex(splitlist);
                rep->getPlaylist()->debug();
            }
        }
        stream_Delete(stream);
    }

    return true;
}
<commit_msg>demux: dash: index time is scaled<commit_after>/*
 * AtomsReader.cpp
 *****************************************************************************
 * Copyright (C) 2014 - VideoLAN authors
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program 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 program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/
#include "AtomsReader.hpp"
#include "mpd/Representation.h"
#include "mpd/MPD.h"

using namespace dash::mp4;
using namespace dash::mpd;

AtomsReader::AtomsReader(vlc_object_t *object_)
{
    object = object_;
    rootbox = NULL;
}

AtomsReader::~AtomsReader()
{
    while(rootbox && rootbox->p_first)
    {
        MP4_Box_t *p_next = rootbox->p_first->p_next;
        MP4_BoxFree( (stream_t *)object, rootbox->p_first );
        rootbox->p_first = p_next;
    }
    delete rootbox;
}

bool AtomsReader::parseBlock(void *buffer, size_t size, BaseRepresentation *rep)
{
    if(!rep)
        return false;

    stream_t *stream = stream_MemoryNew( object, (uint8_t *)buffer, size, true);
    if (stream)
    {
        rootbox = new MP4_Box_t;
        if(!rootbox)
        {
            stream_Delete(stream);
            return false;
        }
        memset(rootbox, 0, sizeof(*rootbox));
        rootbox->i_type = ATOM_root;
        rootbox->i_size = size;
        if ( MP4_ReadBoxContainerChildren( stream, rootbox, 0 ) == 1 )
        {
#ifndef NDEBUG
            MP4_BoxDumpStructure(stream, rootbox);
#endif
            MP4_Box_t *sidxbox = MP4_BoxGet(rootbox, "sidx");
            if (sidxbox)
            {
                Representation::SplitPoint point;
                std::vector<Representation::SplitPoint> splitlist;
                MP4_Box_data_sidx_t *sidx = sidxbox->data.p_sidx;
                point.offset = sidx->i_first_offset;
                point.time = 0;
                for(uint16_t i=0; i<sidx->i_reference_count && sidx->i_timescale; i++)
                {
                    splitlist.push_back(point);
                    point.offset += sidx->p_items[i].i_referenced_size;
                    point.time += CLOCK_FREQ * sidx->p_items[i].i_subsegment_duration /
                                  sidx->i_timescale;
                }
                rep->SplitUsingIndex(splitlist);
                rep->getPlaylist()->debug();
            }
        }
        stream_Delete(stream);
    }

    return true;
}
<|endoftext|>


<commit_before>//===-- OsLogger.cpp --------------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "OsLogger.h"

#if LLDB_USE_OS_LOG

#include <os/log.h>

#include "DNBDefs.h"
#include "DNBLog.h"

#define LLDB_OS_LOG_MAX_BUFFER_LENGTH 256

namespace {
//----------------------------------------------------------------------
// Darwin os_log logging callback that can be registered with
// DNBLogSetLogCallback
//----------------------------------------------------------------------
void DarwinLogCallback(void *baton, uint32_t flags, const char *format,
                       va_list args) {
  if (format == nullptr)
    return;

  static os_log_t g_logger;
  if (!g_logger) {
    g_logger = os_log_create("com.apple.dt.lldb", "debugserver");
    if (!g_logger)
      return;
  }

  os_log_type_t log_type;
  if (flags & DNBLOG_FLAG_FATAL)
    log_type = OS_LOG_TYPE_FAULT;
  else if (flags & DNBLOG_FLAG_ERROR)
    log_type = OS_LOG_TYPE_ERROR;
  else if (flags & DNBLOG_FLAG_WARNING)
    log_type = OS_LOG_TYPE_DEFAULT;
  else if (flags & DNBLOG_FLAG_VERBOSE)
    log_type = OS_LOG_TYPE_DEBUG;
  else
    log_type = OS_LOG_TYPE_DEFAULT;

  // This code is unfortunate.  os_log* only takes static strings, but
  // our current log API isn't set up to make use of that style.
  char buffer[LLDB_OS_LOG_MAX_BUFFER_LENGTH];
  vsnprintf(buffer, sizeof(buffer), format, args);
  os_log_with_type(g_logger, log_type, "%{public}s", buffer);
}
}

DNBCallbackLog OsLogger::GetLogFunction() {
  return _os_log_impl ? DarwinLogCallback : nullptr;
}

#else

DNBCallbackLog OsLogger::GetLogFunction() { return nullptr; }

#endif
<commit_msg>Conditionalized OsLogger.cpp on a modern SDK.<commit_after>//===-- OsLogger.cpp --------------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "OsLogger.h"
#include <Availability.h>

#if (LLDB_USE_OS_LOG) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 101200)

#include <os/log.h>

#include "DNBDefs.h"
#include "DNBLog.h"

#define LLDB_OS_LOG_MAX_BUFFER_LENGTH 256

namespace {
//----------------------------------------------------------------------
// Darwin os_log logging callback that can be registered with
// DNBLogSetLogCallback
//----------------------------------------------------------------------
void DarwinLogCallback(void *baton, uint32_t flags, const char *format,
                       va_list args) {
  if (format == nullptr)
    return;

  static os_log_t g_logger;
  if (!g_logger) {
    g_logger = os_log_create("com.apple.dt.lldb", "debugserver");
    if (!g_logger)
      return;
  }

  os_log_type_t log_type;
  if (flags & DNBLOG_FLAG_FATAL)
    log_type = OS_LOG_TYPE_FAULT;
  else if (flags & DNBLOG_FLAG_ERROR)
    log_type = OS_LOG_TYPE_ERROR;
  else if (flags & DNBLOG_FLAG_WARNING)
    log_type = OS_LOG_TYPE_DEFAULT;
  else if (flags & DNBLOG_FLAG_VERBOSE)
    log_type = OS_LOG_TYPE_DEBUG;
  else
    log_type = OS_LOG_TYPE_DEFAULT;

  // This code is unfortunate.  os_log* only takes static strings, but
  // our current log API isn't set up to make use of that style.
  char buffer[LLDB_OS_LOG_MAX_BUFFER_LENGTH];
  vsnprintf(buffer, sizeof(buffer), format, args);
  os_log_with_type(g_logger, log_type, "%{public}s", buffer);
}
}

DNBCallbackLog OsLogger::GetLogFunction() {
  return _os_log_impl ? DarwinLogCallback : nullptr;
}

#else

DNBCallbackLog OsLogger::GetLogFunction() { return nullptr; }

#endif

<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of meegotouch-controlpanelsoundsettingsapplet.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** 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
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/
#include "soundsettingsapplet.h"

#include <gst/gst.h>
#include <MAction>
#include <QByteArray>

#include "alerttone.h"
#include "alerttonetoplevel.h"
#include "alerttonebrowser.h"
#include "alerttoneappletwidget.h"

#define DEBUG
#define WARNING
#include "../debug.h"

#ifndef UNIT_TEST
#include <MLibrary>
M_LIBRARY
#endif

Q_EXPORT_PLUGIN2(soundsettingsapplet, SoundSettingsApplet)

int    gst_argc = 1;
char** gst_argv = NULL;

SoundSettingsApplet::SoundSettingsApplet()
{
}

SoundSettingsApplet::~SoundSettingsApplet()
{
	gst_deinit ();

    if ((gst_argv != NULL) && (gst_argv[0] != NULL))
    {
        delete[] gst_argv[0];
        delete[] gst_argv;
    }
}

void
SoundSettingsApplet::init()
{
    gst_argv = new char*[2];
    gst_argv[0] = qstrdup ("app");
    gst_argv[1] = NULL;

    gst_init (&gst_argc, &gst_argv);

    m_alertTones = AlertTone::alertTones ();
}

/* widgetId: 0xaaaabbbb where
   0xaaaa is the widget ID and
   0xbbbb is the alert tone index */
DcpWidget *
SoundSettingsApplet::constructWidget(int widgetId)
{
    SYS_DEBUG ("%s: widgetId = %d", SYS_TIME_STR, widgetId);
	AlertToneToplevel *newWidget = NULL;
	int realWidgetId = widgetId / 65536;
	int alertToneIdx = widgetId - realWidgetId * 65536;

	if (m_stack.size() > 0)
		if (((m_stack.top()->getWidgetId() / 65536) == AlertToneBrowser_id      && realWidgetId == AlertToneBrowser_id) ||
		    ((m_stack.top()->getWidgetId() / 65536) == AlertToneAppletWidget_id && realWidgetId != AlertToneBrowser_id))
			return NULL;

	if (AlertToneAppletWidget_id == realWidgetId)
		newWidget = new AlertToneAppletWidget(m_alertTones);
	else
	if (AlertToneBrowser_id == realWidgetId && alertToneIdx >= 0 && alertToneIdx < m_alertTones.size())
		newWidget = new AlertToneBrowser(m_alertTones[alertToneIdx]);
	else
		SYS_WARNING ("Invalid widgetId = %d", widgetId);

	if (newWidget)
    {
		m_stack.push(newWidget);
		connect (newWidget, SIGNAL (destroyed (QObject *)),
                 SLOT (toplevelDestroyed (QObject *)));
	}

    SYS_DEBUG ("%s: done", SYS_TIME_STR);
	return newWidget;
}

void
SoundSettingsApplet::toplevelDestroyed(QObject *goner)
{
	if (m_stack.size() > 0)
		if (goner == qobject_cast<QObject *>(m_stack.top()))
			m_stack.pop();
}

QString
SoundSettingsApplet::title() const
{
        QString title = qtTrId("qtn_sond_sounds");

	if (m_stack.size() > 0)
  	if (m_stack.top())
			title = qobject_cast<AlertToneToplevel *>(m_stack.top())->title();

	return title;
}

QVector<MAction*>
SoundSettingsApplet::viewMenuItems()
{
	QVector<MAction*> vector;

	if (m_stack.size() > 0)
		if (m_stack.top())
			vector = qobject_cast<AlertToneToplevel *>(m_stack.top())->viewMenuItems();

	return vector;
}

DcpBrief *
SoundSettingsApplet::constructBrief (
        int partId)
{
    Q_UNUSED (partId);
    return NULL;
}

<commit_msg>Changes: disable debug<commit_after>/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of meegotouch-controlpanelsoundsettingsapplet.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** 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
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/
#include "soundsettingsapplet.h"

#include <gst/gst.h>
#include <MAction>
#include <QByteArray>

#include "alerttone.h"
#include "alerttonetoplevel.h"
#include "alerttonebrowser.h"
#include "alerttoneappletwidget.h"

#undef DEBUG
#define WARNING
#include "../debug.h"

#ifndef UNIT_TEST
#include <MLibrary>
M_LIBRARY
#endif

Q_EXPORT_PLUGIN2(soundsettingsapplet, SoundSettingsApplet)

int    gst_argc = 1;
char** gst_argv = NULL;

SoundSettingsApplet::SoundSettingsApplet()
{
}

SoundSettingsApplet::~SoundSettingsApplet()
{
	gst_deinit ();

    if ((gst_argv != NULL) && (gst_argv[0] != NULL))
    {
        delete[] gst_argv[0];
        delete[] gst_argv;
    }
}

void
SoundSettingsApplet::init()
{
    gst_argv = new char*[2];
    gst_argv[0] = qstrdup ("app");
    gst_argv[1] = NULL;

    gst_init (&gst_argc, &gst_argv);

    m_alertTones = AlertTone::alertTones ();
}

/* widgetId: 0xaaaabbbb where
   0xaaaa is the widget ID and
   0xbbbb is the alert tone index */
DcpWidget *
SoundSettingsApplet::constructWidget(int widgetId)
{
    SYS_DEBUG ("%s: widgetId = %d", SYS_TIME_STR, widgetId);
	AlertToneToplevel *newWidget = NULL;
	int realWidgetId = widgetId / 65536;
	int alertToneIdx = widgetId - realWidgetId * 65536;

	if (m_stack.size() > 0)
		if (((m_stack.top()->getWidgetId() / 65536) == AlertToneBrowser_id      && realWidgetId == AlertToneBrowser_id) ||
		    ((m_stack.top()->getWidgetId() / 65536) == AlertToneAppletWidget_id && realWidgetId != AlertToneBrowser_id))
			return NULL;

	if (AlertToneAppletWidget_id == realWidgetId)
		newWidget = new AlertToneAppletWidget(m_alertTones);
	else
	if (AlertToneBrowser_id == realWidgetId && alertToneIdx >= 0 && alertToneIdx < m_alertTones.size())
		newWidget = new AlertToneBrowser(m_alertTones[alertToneIdx]);
	else
		SYS_WARNING ("Invalid widgetId = %d", widgetId);

	if (newWidget)
    {
		m_stack.push(newWidget);
		connect (newWidget, SIGNAL (destroyed (QObject *)),
                 SLOT (toplevelDestroyed (QObject *)));
	}

    SYS_DEBUG ("%s: done", SYS_TIME_STR);
	return newWidget;
}

void
SoundSettingsApplet::toplevelDestroyed(QObject *goner)
{
	if (m_stack.size() > 0)
		if (goner == qobject_cast<QObject *>(m_stack.top()))
			m_stack.pop();
}

QString
SoundSettingsApplet::title() const
{
        QString title = qtTrId("qtn_sond_sounds");

	if (m_stack.size() > 0)
  	if (m_stack.top())
			title = qobject_cast<AlertToneToplevel *>(m_stack.top())->title();

	return title;
}

QVector<MAction*>
SoundSettingsApplet::viewMenuItems()
{
	QVector<MAction*> vector;

	if (m_stack.size() > 0)
		if (m_stack.top())
			vector = qobject_cast<AlertToneToplevel *>(m_stack.top())->viewMenuItems();

	return vector;
}

DcpBrief *
SoundSettingsApplet::constructBrief (
        int partId)
{
    Q_UNUSED (partId);
    return NULL;
}

<|endoftext|>


<commit_before>// Copyright (c) 2011-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#if defined(HAVE_CONFIG_H)
#include "config/bitcoin-config.h"
#endif

#include "intro.h"
#include "ui_intro.h"

#include "guiutil.h"

#include "util.h"

#include <boost/filesystem.hpp>

#include <QFileDialog>
#include <QSettings>
#include <QMessageBox>

#include <cmath>

static const uint64_t GB_BYTES = 1000000000LL;
/* Minimum free space (in GB) needed for data directory */
static const uint64_t BLOCK_CHAIN_SIZE = 50;
/* Minimum free space (in GB) needed for data directory when pruned; Does not include prune target */
static const uint64_t CHAIN_STATE_SIZE = 2;
/* Total required space (in GB) depending on user choice (prune, not prune) */
static uint64_t requiredSpace;

/* Check free space asynchronously to prevent hanging the UI thread.

   Up to one request to check a path is in flight to this thread; when the check()
   function runs, the current path is requested from the associated Intro object.
   The reply is sent back through a signal.

   This ensures that no queue of checking requests is built up while the user is
   still entering the path, and that always the most recently entered path is checked as
   soon as the thread becomes available.
*/
class FreespaceChecker : public QObject
{
    Q_OBJECT

public:
    FreespaceChecker(Intro *intro);

    enum Status {
        ST_OK,
        ST_ERROR
    };

public Q_SLOTS:
    void check();

Q_SIGNALS:
    void reply(int status, const QString &message, quint64 available);

private:
    Intro *intro;
};

#include "intro.moc"

FreespaceChecker::FreespaceChecker(Intro *_intro)
{
    this->intro = _intro;
}

void FreespaceChecker::check()
{
    namespace fs = boost::filesystem;
    QString dataDirStr = intro->getPathToCheck();
    fs::path dataDir = GUIUtil::qstringToBoostPath(dataDirStr);
    uint64_t freeBytesAvailable = 0;
    int replyStatus = ST_OK;
    QString replyMessage = tr("A new data directory will be created.");

    /* Find first parent that exists, so that fs::space does not fail */
    fs::path parentDir = dataDir;
    fs::path parentDirOld = fs::path();
    while(parentDir.has_parent_path() && !fs::exists(parentDir))
    {
        parentDir = parentDir.parent_path();

        /* Check if we make any progress, break if not to prevent an infinite loop here */
        if (parentDirOld == parentDir)
            break;

        parentDirOld = parentDir;
    }

    try {
        freeBytesAvailable = fs::space(parentDir).available;
        if(fs::exists(dataDir))
        {
            if(fs::is_directory(dataDir))
            {
                QString separator = "" + QDir::toNativeSeparators("/") + tr("name") + "";
                replyStatus = ST_OK;
                replyMessage = tr("Directory already exists. Add %1 if you intend to create a new directory here.").arg(separator);
            } else {
                replyStatus = ST_ERROR;
                replyMessage = tr("Path already exists, and is not a directory.");
            }
        }
    } catch (const fs::filesystem_error&)
    {
        /* Parent directory does not exist or is not accessible */
        replyStatus = ST_ERROR;
        replyMessage = tr("Cannot create data directory here.");
    }
    Q_EMIT reply(replyStatus, replyMessage, freeBytesAvailable);
}

Intro::Intro(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Intro),
    thread(0),
    signalled(false)
{
    ui->setupUi(this);
    ui->welcomeLabel->setText(ui->welcomeLabel->text().arg(tr(PACKAGE_NAME)));
    ui->storageLabel->setText(ui->storageLabel->text().arg(tr(PACKAGE_NAME)));
    uint64_t pruneTarget = std::max<int64_t>(0, GetArg("-prune", 0));
    requiredSpace = BLOCK_CHAIN_SIZE;
    if (pruneTarget) {
        uint64_t prunedGBs = std::ceil(pruneTarget * 1024 * 1024.0 / GB_BYTES);
        if (prunedGBs <= requiredSpace) {
            requiredSpace = prunedGBs;
        }
    }
    requiredSpace += CHAIN_STATE_SIZE;
    ui->sizeWarningLabel->setText(ui->sizeWarningLabel->text().arg(tr(PACKAGE_NAME)).arg(requiredSpace));
    startThread();
}

Intro::~Intro()
{
    delete ui;
    /* Ensure thread is finished before it is deleted */
    Q_EMIT stopThread();
    thread->wait();
}

QString Intro::getDataDirectory()
{
    return ui->dataDirectory->text();
}

void Intro::setDataDirectory(const QString &dataDir)
{
    ui->dataDirectory->setText(dataDir);
    if(dataDir == getDefaultDataDirectory())
    {
        ui->dataDirDefault->setChecked(true);
        ui->dataDirectory->setEnabled(false);
        ui->ellipsisButton->setEnabled(false);
    } else {
        ui->dataDirCustom->setChecked(true);
        ui->dataDirectory->setEnabled(true);
        ui->ellipsisButton->setEnabled(true);
    }
}

QString Intro::getDefaultDataDirectory()
{
    return GUIUtil::boostPathToQString(GetDefaultDataDir());
}

bool Intro::pickDataDirectory()
{
    namespace fs = boost::filesystem;
    QSettings settings;
    /* If data directory provided on command line, no need to look at settings
       or show a picking dialog */
    if(!GetArg("-datadir", "").empty())
        return true;
    /* 1) Default data directory for operating system */
    QString dataDir = getDefaultDataDirectory();
    /* 2) Allow QSettings to override default dir */
    dataDir = settings.value("strDataDir", dataDir).toString();

    if(!fs::exists(GUIUtil::qstringToBoostPath(dataDir)) || GetBoolArg("-choosedatadir", DEFAULT_CHOOSE_DATADIR) || settings.value("fReset", false).toBool() || GetBoolArg("-resetguisettings", false))
    {
        /* If current default data directory does not exist, let the user choose one */
        Intro intro;
        intro.setDataDirectory(dataDir);
        intro.setWindowIcon(QIcon(":icons/bitcoin"));

        while(true)
        {
            if(!intro.exec())
            {
                /* Cancel clicked */
                return false;
            }
            dataDir = intro.getDataDirectory();
            try {
                TryCreateDirectory(GUIUtil::qstringToBoostPath(dataDir));
                break;
            } catch (const fs::filesystem_error&) {
                QMessageBox::critical(0, tr(PACKAGE_NAME),
                    tr("Error: Specified data directory \"%1\" cannot be created.").arg(dataDir));
                /* fall through, back to choosing screen */
            }
        }

        settings.setValue("strDataDir", dataDir);
        settings.setValue("fReset", false);
    }
    /* Only override -datadir if different from the default, to make it possible to
     * override -datadir in the bitcoin.conf file in the default data directory
     * (to be consistent with bitcoind behavior)
     */
    if(dataDir != getDefaultDataDirectory())
        SoftSetArg("-datadir", GUIUtil::qstringToBoostPath(dataDir).string()); // use OS locale for path setting
    return true;
}

void Intro::setStatus(int status, const QString &message, quint64 bytesAvailable)
{
    switch(status)
    {
    case FreespaceChecker::ST_OK:
        ui->errorMessage->setText(message);
        ui->errorMessage->setStyleSheet("");
        break;
    case FreespaceChecker::ST_ERROR:
        ui->errorMessage->setText(tr("Error") + ": " + message);
        ui->errorMessage->setStyleSheet("QLabel { color: #800000 }");
        break;
    }
    /* Indicate number of bytes available */
    if(status == FreespaceChecker::ST_ERROR)
    {
        ui->freeSpace->setText("");
    } else {
        QString freeString = tr("%n GB of free space available", "", bytesAvailable/GB_BYTES);
        if(bytesAvailable < requiredSpace * GB_BYTES)
        {
            freeString += " " + tr("(of %n GB needed)", "", requiredSpace);
            ui->freeSpace->setStyleSheet("QLabel { color: #800000 }");
        } else {
            ui->freeSpace->setStyleSheet("");
        }
        ui->freeSpace->setText(freeString + ".");
    }
    /* Don't allow confirm in ERROR state */
    ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(status != FreespaceChecker::ST_ERROR);
}

void Intro::on_dataDirectory_textChanged(const QString &dataDirStr)
{
    /* Disable OK button until check result comes in */
    ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
    checkPath(dataDirStr);
}

void Intro::on_ellipsisButton_clicked()
{
    QString dir = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(0, "Choose data directory", ui->dataDirectory->text()));
    if(!dir.isEmpty())
        ui->dataDirectory->setText(dir);
}

void Intro::on_dataDirDefault_clicked()
{
    setDataDirectory(getDefaultDataDirectory());
}

void Intro::on_dataDirCustom_clicked()
{
    ui->dataDirectory->setEnabled(true);
    ui->ellipsisButton->setEnabled(true);
}

void Intro::startThread()
{
    thread = new QThread(this);
    FreespaceChecker *executor = new FreespaceChecker(this);
    executor->moveToThread(thread);

    connect(executor, SIGNAL(reply(int,QString,quint64)), this, SLOT(setStatus(int,QString,quint64)));
    connect(this, SIGNAL(requestCheck()), executor, SLOT(check()));
    /*  make sure executor object is deleted in its own thread */
    connect(this, SIGNAL(stopThread()), executor, SLOT(deleteLater()));
    connect(this, SIGNAL(stopThread()), thread, SLOT(quit()));

    thread->start();
}

void Intro::checkPath(const QString &dataDir)
{
    mutex.lock();
    pathToCheck = dataDir;
    if(!signalled)
    {
        signalled = true;
        Q_EMIT requestCheck();
    }
    mutex.unlock();
}

QString Intro::getPathToCheck()
{
    QString retval;
    mutex.lock();
    retval = pathToCheck;
    signalled = false; /* new request can be queued now */
    mutex.unlock();
    return retval;
}
<commit_msg>Update src/qt/intro.cpp<commit_after>// Copyright (c) 2011-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#if defined(HAVE_CONFIG_H)
#include "config/bitcoin-config.h"
#endif

#include "intro.h"
#include "ui_intro.h"

#include "guiutil.h"

#include "util.h"

#include <boost/filesystem.hpp>

#include <QFileDialog>
#include <QSettings>
#include <QMessageBox>

#include <cmath>

static const uint64_t GB_BYTES = 1000000000LL;
/* Minimum free space (in GB) needed for data directory */
static const uint64_t BLOCK_CHAIN_SIZE = 55;
/* Minimum free space (in GB) needed for data directory when pruned; Does not include prune target */
static const uint64_t CHAIN_STATE_SIZE = 2;
/* Total required space (in GB) depending on user choice (prune, not prune) */
static uint64_t requiredSpace;

/* Check free space asynchronously to prevent hanging the UI thread.

   Up to one request to check a path is in flight to this thread; when the check()
   function runs, the current path is requested from the associated Intro object.
   The reply is sent back through a signal.

   This ensures that no queue of checking requests is built up while the user is
   still entering the path, and that always the most recently entered path is checked as
   soon as the thread becomes available.
*/
class FreespaceChecker : public QObject
{
    Q_OBJECT

public:
    FreespaceChecker(Intro *intro);

    enum Status {
        ST_OK,
        ST_ERROR
    };

public Q_SLOTS:
    void check();

Q_SIGNALS:
    void reply(int status, const QString &message, quint64 available);

private:
    Intro *intro;
};

#include "intro.moc"

FreespaceChecker::FreespaceChecker(Intro *_intro)
{
    this->intro = _intro;
}

void FreespaceChecker::check()
{
    namespace fs = boost::filesystem;
    QString dataDirStr = intro->getPathToCheck();
    fs::path dataDir = GUIUtil::qstringToBoostPath(dataDirStr);
    uint64_t freeBytesAvailable = 0;
    int replyStatus = ST_OK;
    QString replyMessage = tr("A new data directory will be created.");

    /* Find first parent that exists, so that fs::space does not fail */
    fs::path parentDir = dataDir;
    fs::path parentDirOld = fs::path();
    while(parentDir.has_parent_path() && !fs::exists(parentDir))
    {
        parentDir = parentDir.parent_path();

        /* Check if we make any progress, break if not to prevent an infinite loop here */
        if (parentDirOld == parentDir)
            break;

        parentDirOld = parentDir;
    }

    try {
        freeBytesAvailable = fs::space(parentDir).available;
        if(fs::exists(dataDir))
        {
            if(fs::is_directory(dataDir))
            {
                QString separator = "" + QDir::toNativeSeparators("/") + tr("name") + "";
                replyStatus = ST_OK;
                replyMessage = tr("Directory already exists. Add %1 if you intend to create a new directory here.").arg(separator);
            } else {
                replyStatus = ST_ERROR;
                replyMessage = tr("Path already exists, and is not a directory.");
            }
        }
    } catch (const fs::filesystem_error&)
    {
        /* Parent directory does not exist or is not accessible */
        replyStatus = ST_ERROR;
        replyMessage = tr("Cannot create data directory here.");
    }
    Q_EMIT reply(replyStatus, replyMessage, freeBytesAvailable);
}

Intro::Intro(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Intro),
    thread(0),
    signalled(false)
{
    ui->setupUi(this);
    ui->welcomeLabel->setText(ui->welcomeLabel->text().arg(tr(PACKAGE_NAME)));
    ui->storageLabel->setText(ui->storageLabel->text().arg(tr(PACKAGE_NAME)));
    uint64_t pruneTarget = std::max<int64_t>(0, GetArg("-prune", 0));
    requiredSpace = BLOCK_CHAIN_SIZE;
    if (pruneTarget) {
        uint64_t prunedGBs = std::ceil(pruneTarget * 1024 * 1024.0 / GB_BYTES);
        if (prunedGBs <= requiredSpace) {
            requiredSpace = prunedGBs;
        }
    }
    requiredSpace += CHAIN_STATE_SIZE;
    ui->sizeWarningLabel->setText(ui->sizeWarningLabel->text().arg(tr(PACKAGE_NAME)).arg(requiredSpace));
    startThread();
}

Intro::~Intro()
{
    delete ui;
    /* Ensure thread is finished before it is deleted */
    Q_EMIT stopThread();
    thread->wait();
}

QString Intro::getDataDirectory()
{
    return ui->dataDirectory->text();
}

void Intro::setDataDirectory(const QString &dataDir)
{
    ui->dataDirectory->setText(dataDir);
    if(dataDir == getDefaultDataDirectory())
    {
        ui->dataDirDefault->setChecked(true);
        ui->dataDirectory->setEnabled(false);
        ui->ellipsisButton->setEnabled(false);
    } else {
        ui->dataDirCustom->setChecked(true);
        ui->dataDirectory->setEnabled(true);
        ui->ellipsisButton->setEnabled(true);
    }
}

QString Intro::getDefaultDataDirectory()
{
    return GUIUtil::boostPathToQString(GetDefaultDataDir());
}

bool Intro::pickDataDirectory()
{
    namespace fs = boost::filesystem;
    QSettings settings;
    /* If data directory provided on command line, no need to look at settings
       or show a picking dialog */
    if(!GetArg("-datadir", "").empty())
        return true;
    /* 1) Default data directory for operating system */
    QString dataDir = getDefaultDataDirectory();
    /* 2) Allow QSettings to override default dir */
    dataDir = settings.value("strDataDir", dataDir).toString();

    if(!fs::exists(GUIUtil::qstringToBoostPath(dataDir)) || GetBoolArg("-choosedatadir", DEFAULT_CHOOSE_DATADIR) || settings.value("fReset", false).toBool() || GetBoolArg("-resetguisettings", false))
    {
        /* If current default data directory does not exist, let the user choose one */
        Intro intro;
        intro.setDataDirectory(dataDir);
        intro.setWindowIcon(QIcon(":icons/bitcoin"));

        while(true)
        {
            if(!intro.exec())
            {
                /* Cancel clicked */
                return false;
            }
            dataDir = intro.getDataDirectory();
            try {
                TryCreateDirectory(GUIUtil::qstringToBoostPath(dataDir));
                break;
            } catch (const fs::filesystem_error&) {
                QMessageBox::critical(0, tr(PACKAGE_NAME),
                    tr("Error: Specified data directory \"%1\" cannot be created.").arg(dataDir));
                /* fall through, back to choosing screen */
            }
        }

        settings.setValue("strDataDir", dataDir);
        settings.setValue("fReset", false);
    }
    /* Only override -datadir if different from the default, to make it possible to
     * override -datadir in the bitcoin.conf file in the default data directory
     * (to be consistent with bitcoind behavior)
     */
    if(dataDir != getDefaultDataDirectory())
        SoftSetArg("-datadir", GUIUtil::qstringToBoostPath(dataDir).string()); // use OS locale for path setting
    return true;
}

void Intro::setStatus(int status, const QString &message, quint64 bytesAvailable)
{
    switch(status)
    {
    case FreespaceChecker::ST_OK:
        ui->errorMessage->setText(message);
        ui->errorMessage->setStyleSheet("");
        break;
    case FreespaceChecker::ST_ERROR:
        ui->errorMessage->setText(tr("Error") + ": " + message);
        ui->errorMessage->setStyleSheet("QLabel { color: #800000 }");
        break;
    }
    /* Indicate number of bytes available */
    if(status == FreespaceChecker::ST_ERROR)
    {
        ui->freeSpace->setText("");
    } else {
        QString freeString = tr("%n GB of free space available", "", bytesAvailable/GB_BYTES);
        if(bytesAvailable < requiredSpace * GB_BYTES)
        {
            freeString += " " + tr("(of %n GB needed)", "", requiredSpace);
            ui->freeSpace->setStyleSheet("QLabel { color: #800000 }");
        } else {
            ui->freeSpace->setStyleSheet("");
        }
        ui->freeSpace->setText(freeString + ".");
    }
    /* Don't allow confirm in ERROR state */
    ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(status != FreespaceChecker::ST_ERROR);
}

void Intro::on_dataDirectory_textChanged(const QString &dataDirStr)
{
    /* Disable OK button until check result comes in */
    ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
    checkPath(dataDirStr);
}

void Intro::on_ellipsisButton_clicked()
{
    QString dir = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(0, "Choose data directory", ui->dataDirectory->text()));
    if(!dir.isEmpty())
        ui->dataDirectory->setText(dir);
}

void Intro::on_dataDirDefault_clicked()
{
    setDataDirectory(getDefaultDataDirectory());
}

void Intro::on_dataDirCustom_clicked()
{
    ui->dataDirectory->setEnabled(true);
    ui->ellipsisButton->setEnabled(true);
}

void Intro::startThread()
{
    thread = new QThread(this);
    FreespaceChecker *executor = new FreespaceChecker(this);
    executor->moveToThread(thread);

    connect(executor, SIGNAL(reply(int,QString,quint64)), this, SLOT(setStatus(int,QString,quint64)));
    connect(this, SIGNAL(requestCheck()), executor, SLOT(check()));
    /*  make sure executor object is deleted in its own thread */
    connect(this, SIGNAL(stopThread()), executor, SLOT(deleteLater()));
    connect(this, SIGNAL(stopThread()), thread, SLOT(quit()));

    thread->start();
}

void Intro::checkPath(const QString &dataDir)
{
    mutex.lock();
    pathToCheck = dataDir;
    if(!signalled)
    {
        signalled = true;
        Q_EMIT requestCheck();
    }
    mutex.unlock();
}

QString Intro::getPathToCheck()
{
    QString retval;
    mutex.lock();
    retval = pathToCheck;
    signalled = false; /* new request can be queued now */
    mutex.unlock();
    return retval;
}
<|endoftext|>


<commit_before>#include "Shader.h"
#include "renderers/utils/GLResourceManager.h"
#include "utils/Log.h"

#include <vector>

namespace carto {

    Shader::~Shader() {
    }

    GLuint Shader::getProgId() const {
        create();
        return _progId;
    }

    GLuint Shader::getUniformLoc(const std::string& uniformName) const {
        auto it = _uniformMap.find(uniformName);
        if (it == _uniformMap.end()) {
            Log::Errorf("Shader::getUniformLoc: Uniform '%s' not found in shader '%s'", uniformName.c_str(), _name.c_str());
            return 0;
        }
        return it->second;
    }

    GLuint Shader::getAttribLoc(const std::string& attribName) const {
        auto it = _attribMap.find(attribName);
        if (it == _attribMap.end()) {
            Log::Errorf("Shader::getAttribLoc: Attribute '%s' not found in shader '%s'", attribName.c_str(), _name.c_str());
            return 0;
        }
        return it->second;
    }

    Shader::Shader(const std::weak_ptr<GLResourceManager>& manager, const std::string& name, const std::string& vertSource, const std::string& fragSource) :
        GLResource(manager),
        _name(name),
        _vertSource(vertSource),
        _fragSource(fragSource),
        _progId(0),
        _vertShaderId(0),
        _fragShaderId(0),
        _uniformMap(),
        _attribMap()
    {
    }

    void Shader::create() const {
        if (_progId == 0) {
            _vertShaderId = LoadShader(_name, _vertSource, GL_VERTEX_SHADER);
            _fragShaderId = LoadShader(_name, _fragSource, GL_FRAGMENT_SHADER);
            _progId = LoadProg(_name, _vertShaderId, _fragShaderId);

            registerVars(_progId);
        }
    }

    void Shader::destroy() const {
        if (_vertShaderId) {
            glDeleteShader(_vertShaderId);
            _vertShaderId = 0;
        }

        if (_fragShaderId) {
            glDeleteShader(_fragShaderId);
            _fragShaderId = 0;
        }

        if (_progId) {
            glDeleteProgram(_progId);
            _progId = 0;
        }

        _uniformMap.clear();
        _attribMap.clear();

        GLContext::CheckGLError("Shader::destroy");
    }

    void Shader::registerVars(GLuint progId) const {
        enum { VAR_NAME_BUF_SIZE = 256 };
        char varNameBuf[VAR_NAME_BUF_SIZE];
        GLint count = 0;

        // Assign a location for every uniform variable, save them to map
        glGetProgramiv(progId, GL_ACTIVE_UNIFORMS, &count);
        for (GLuint tsj = 0; tsj < (GLuint) count; tsj++) {
            GLsizei actualLength = 0;
            GLint size = 0;
            GLenum type = 0;
            glGetActiveUniform(progId, tsj, VAR_NAME_BUF_SIZE, &actualLength, &size, &type, varNameBuf);
            std::string varName(varNameBuf, actualLength);
            GLuint loc = glGetUniformLocation(progId, varName.c_str());
            _uniformMap[varName] = loc;
        }

        // Assign a location for every attribute variable, save them to map
        glGetProgramiv(progId, GL_ACTIVE_ATTRIBUTES, &count);
        for (GLuint tsj = 0; tsj < (GLuint) count; tsj++) {
            GLsizei actualLength = 0;
            GLint size = 0;
            GLenum type = 0;
            glGetActiveAttrib(progId, tsj, VAR_NAME_BUF_SIZE, &actualLength, &size, &type, varNameBuf);
            std::string varName(varNameBuf, actualLength);
            GLuint loc = glGetAttribLocation(progId, varName.c_str());
            _attribMap[varName] = loc;
        }

        GLContext::CheckGLError("Shader::registerVars");
    }

    GLuint Shader::LoadProg(const std::string& name, GLuint vertShaderId, GLuint fragShaderId) {
        GLuint progId = glCreateProgram();
        if (progId == 0) {
            Log::Errorf("Shader::LoadProg: Failed to create shader program in '%s' shader", name.c_str());
            return 0;
        }

        glAttachShader(progId, vertShaderId);
        glAttachShader(progId, fragShaderId);
        glLinkProgram(progId);
        GLint linked = GL_FALSE;
        glGetProgramiv(progId, GL_LINK_STATUS, &linked);
        if (linked == GL_FALSE) {
            GLint infoLen = 0;
            glGetShaderiv(progId, GL_INFO_LOG_LENGTH, &infoLen);
            if (infoLen > 0) {
                std::vector<char> infoBuf(infoLen);
                glGetProgramInfoLog(progId, infoLen, NULL, infoBuf.data());
                Log::Errorf("Shader::LoadProg: Failed to link shader program in '%s' shader \n Error: %s ", name.c_str(), infoBuf.data());
            }
            glDeleteProgram(progId);
            progId = 0;
        }

        GLContext::CheckGLError("Shader::LoadProg");

        return progId;
    }

    GLuint Shader::LoadShader(const std::string& name, const std::string& source, GLenum shaderType) {
        GLuint shaderId = glCreateShader(shaderType);
        if (shaderId == 0) {
            Log::Errorf("Shader::LoadShader: Failed to create shader type %i in '%s' shader", shaderType, name.c_str());
            return 0;
        }

        const char* sourceBuf = source.data();
        glShaderSource(shaderId, 1, &sourceBuf, NULL);

        glCompileShader(shaderId);
        GLint compiled = GL_FALSE;
        glGetShaderiv(shaderId, GL_COMPILE_STATUS, &compiled);
        if (compiled == GL_FALSE) {
            GLint infoLen = 0;
            glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &infoLen);
            if (infoLen > 0) {
                std::vector<char> infoBuf(infoLen);
                glGetShaderInfoLog(shaderId, infoLen, NULL, infoBuf.data());
                Log::Errorf("Shader::LoadShader: Failed to compile shader type %i in '%s' shader \n Error: %s ", shaderType, name.c_str(), infoBuf.data());
            }
            glDeleteShader(shaderId);
            shaderId = 0;
        }

        GLContext::CheckGLError("Shader::LoadShader");

        return shaderId;
    }

}
<commit_msg>Minor cleanup of the Shader wrapper<commit_after>#include "Shader.h"
#include "renderers/utils/GLResourceManager.h"
#include "utils/Log.h"

#include <vector>

namespace carto {

    Shader::~Shader() {
    }

    GLuint Shader::getProgId() const {
        create();
        return _progId;
    }

    GLuint Shader::getUniformLoc(const std::string& uniformName) const {
        create();
        auto it = _uniformMap.find(uniformName);
        if (it == _uniformMap.end()) {
            Log::Errorf("Shader::getUniformLoc: Uniform '%s' not found in shader '%s'", uniformName.c_str(), _name.c_str());
            return 0;
        }
        return it->second;
    }

    GLuint Shader::getAttribLoc(const std::string& attribName) const {
        create();
        auto it = _attribMap.find(attribName);
        if (it == _attribMap.end()) {
            Log::Errorf("Shader::getAttribLoc: Attribute '%s' not found in shader '%s'", attribName.c_str(), _name.c_str());
            return 0;
        }
        return it->second;
    }

    Shader::Shader(const std::weak_ptr<GLResourceManager>& manager, const std::string& name, const std::string& vertSource, const std::string& fragSource) :
        GLResource(manager),
        _name(name),
        _vertSource(vertSource),
        _fragSource(fragSource),
        _progId(0),
        _vertShaderId(0),
        _fragShaderId(0),
        _uniformMap(),
        _attribMap()
    {
    }

    void Shader::create() const {
        enum { VAR_NAME_BUF_SIZE = 256 };

        if (_vertShaderId == 0) {
            _vertShaderId = LoadShader(_name, _vertSource, GL_VERTEX_SHADER);
        }

        if (_fragShaderId == 0) {
            _fragShaderId = LoadShader(_name, _fragSource, GL_FRAGMENT_SHADER);
        }

        if (_progId == 0) {
            _progId = LoadProg(_name, _vertShaderId, _fragShaderId);

            // Assign a location for every uniform variable, save them to map
            GLint uniformCount = 0;
            glGetProgramiv(_progId, GL_ACTIVE_UNIFORMS, &uniformCount);
            for (GLuint tsj = 0; tsj < (GLuint) uniformCount; tsj++) {
                char varNameBuf[VAR_NAME_BUF_SIZE];
                GLsizei actualLength = 0;
                GLint size = 0;
                GLenum type = 0;
                glGetActiveUniform(_progId, tsj, VAR_NAME_BUF_SIZE, &actualLength, &size, &type, varNameBuf);
                std::string varName(varNameBuf, actualLength);
                GLuint loc = glGetUniformLocation(_progId, varName.c_str());
                _uniformMap[varName] = loc;
            }

            // Assign a location for every attribute variable, save them to map
            GLint attribCount = 0;
            glGetProgramiv(_progId, GL_ACTIVE_ATTRIBUTES, &attribCount);
            for (GLuint tsj = 0; tsj < (GLuint) attribCount; tsj++) {
                char varNameBuf[VAR_NAME_BUF_SIZE];
                GLsizei actualLength = 0;
                GLint size = 0;
                GLenum type = 0;
                glGetActiveAttrib(_progId, tsj, VAR_NAME_BUF_SIZE, &actualLength, &size, &type, varNameBuf);
                std::string varName(varNameBuf, actualLength);
                GLuint loc = glGetAttribLocation(_progId, varName.c_str());
                _attribMap[varName] = loc;
            }

            GLContext::CheckGLError("Shader::create");
        }
    }

    void Shader::destroy() const {
        if (_vertShaderId != 0) {
            glDeleteShader(_vertShaderId);
            _vertShaderId = 0;
        }

        if (_fragShaderId != 0) {
            glDeleteShader(_fragShaderId);
            _fragShaderId = 0;
        }

        if (_progId != 0) {
            glDeleteProgram(_progId);
            _progId = 0;

            _uniformMap.clear();
            _attribMap.clear();

            GLContext::CheckGLError("Shader::destroy");
        }
    }

    GLuint Shader::LoadProg(const std::string& name, GLuint vertShaderId, GLuint fragShaderId) {
        GLuint progId = glCreateProgram();
        if (progId == 0) {
            Log::Errorf("Shader::LoadProg: Failed to create shader program in '%s' shader", name.c_str());
            return 0;
        }

        glAttachShader(progId, vertShaderId);
        glAttachShader(progId, fragShaderId);
        glLinkProgram(progId);
        GLint linked = GL_FALSE;
        glGetProgramiv(progId, GL_LINK_STATUS, &linked);
        if (linked == GL_FALSE) {
            GLint infoLen = 0;
            glGetShaderiv(progId, GL_INFO_LOG_LENGTH, &infoLen);
            if (infoLen > 0) {
                std::vector<char> infoBuf(infoLen);
                glGetProgramInfoLog(progId, infoLen, NULL, infoBuf.data());
                Log::Errorf("Shader::LoadProg: Failed to link shader program in '%s' shader \n Error: %s ", name.c_str(), infoBuf.data());
            }
            glDeleteProgram(progId);
            progId = 0;
        }

        GLContext::CheckGLError("Shader::LoadProg");

        return progId;
    }

    GLuint Shader::LoadShader(const std::string& name, const std::string& source, GLenum shaderType) {
        GLuint shaderId = glCreateShader(shaderType);
        if (shaderId == 0) {
            Log::Errorf("Shader::LoadShader: Failed to create shader type %i in '%s' shader", shaderType, name.c_str());
            return 0;
        }

        const char* sourceBuf = source.data();
        glShaderSource(shaderId, 1, &sourceBuf, NULL);

        glCompileShader(shaderId);
        GLint compiled = GL_FALSE;
        glGetShaderiv(shaderId, GL_COMPILE_STATUS, &compiled);
        if (compiled == GL_FALSE) {
            GLint infoLen = 0;
            glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &infoLen);
            if (infoLen > 0) {
                std::vector<char> infoBuf(infoLen);
                glGetShaderInfoLog(shaderId, infoLen, NULL, infoBuf.data());
                Log::Errorf("Shader::LoadShader: Failed to compile shader type %i in '%s' shader \n Error: %s ", shaderType, name.c_str(), infoBuf.data());
            }
            glDeleteShader(shaderId);
            shaderId = 0;
        }

        GLContext::CheckGLError("Shader::LoadShader");

        return shaderId;
    }

}
<|endoftext|>


<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2017 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. 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.
 *
 * 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 <modules/animationqt/sequenceeditorpanel/keyframeeditorwidget.h>
#include <modules/animationqt/sequenceeditorpanel/sequenceeditorwidget.h>
#include <modules/animation/datastructures/propertytrack.h>
#include <modules/animation/datastructures/controltrack.h>

#include <modules/qtwidgets/properties/ordinalpropertywidgetqt.h>

#include <inviwo/core/properties/property.h>
#include <inviwo/core/properties/propertywidgetfactory.h>

#include <warn/push>
#include <warn/ignore/all>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QDoubleSpinBox>
#include <QComboBox>
#include <warn/pop>

namespace inviwo {

namespace animation {
KeyframeEditorWidget::KeyframeEditorWidget(Keyframe &keyframe, SequenceEditorWidget *parent)
    : QWidget(parent), keyframe_(keyframe), sequenceEditorWidget_(parent) {

    setObjectName("KeyframeEditorWidget");

    keyframe.addObserver(this);

    layout_ = new QHBoxLayout();

    timeSpinner_ = new QDoubleSpinBox();
    timeSpinner_->setValue(keyframe.getTime().count());
    timeSpinner_->setSuffix("s");
    timeSpinner_->setSingleStep(0.1);
    timeSpinner_->setDecimals(5);

    void (QDoubleSpinBox::*signal)(double) = &QDoubleSpinBox::valueChanged;
    connect(timeSpinner_, signal, this, [this](double t){
        keyframe_.setTime(Seconds(t));
    });

    layout_->addWidget(timeSpinner_);

    if (auto propTrack = dynamic_cast<BasePropertyTrack *>(&parent->getTrack())) {
        auto baseProperty = propTrack->getProperty();
        property_.reset(baseProperty->clone());
		propTrack->setOtherProperty(property_.get(),&keyframe);
        property_->onChange([b = baseProperty, p = property_.get(),t= propTrack,k=&keyframe_]() {
            b->set(p);
            t->updateKeyframeFromProperty(p,k);
        });
        property_->setOwner(nullptr);

        auto propWidget =
            util::getInviwoApplication()->getPropertyWidgetFactory()->create(property_.get());
        propertyWidget_ = static_cast<PropertyWidgetQt *>(propWidget.release());

        if (auto label = propertyWidget_->findChild<EditableLabelQt *>()) {
            label->setVisible(false);
        }

        layout_->addWidget(propertyWidget_);
	}
	else if (auto ctrlTrack = dynamic_cast<ControlTrack*>(&parent->getTrack())) {
		// Assume that we only have ControlKeyframes within ControlTracks
		auto& ctrlKey = *static_cast<ControlKeyframe*>(&keyframe);

		actionWidget_ = new QComboBox();
		actionWidget_->addItems({ "Pause", "Jump To", "Script" });
		actionWidget_->setCurrentIndex(static_cast<int>(ctrlKey.getAction()));

		jumpToWidget_ = new QDoubleSpinBox();
		jumpToWidget_->setValue(ctrlKey.getPayload().jumpToTime.count());
		jumpToWidget_->setSuffix("s");
		jumpToWidget_->setSingleStep(0.1);
		jumpToWidget_->setDecimals(5);
		jumpToWidget_->setVisible(ctrlKey.getAction() == ControlAction::JumpTo);

		connect(actionWidget_, static_cast<void(QComboBox::*)(int)>(&QComboBox::activated),
			[this, &ctrlKey](int idx) {
			ctrlKey.setAction(static_cast<ControlAction>(idx));
			jumpToWidget_->setVisible(ctrlKey.getAction() == ControlAction::JumpTo);
		});

		connect(timeSpinner_, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
			this, [this, &ctrlKey](double t) {
			ControlPayload payload;
			payload.jumpToTime = Seconds{ t };
			ctrlKey.setPayload(payload);
		});

		layout_->addWidget(actionWidget_);
		layout_->addWidget(jumpToWidget_);
	}

    setLayout(layout_);
}

KeyframeEditorWidget::~KeyframeEditorWidget() {
    if(propertyWidget_){
        layout_->removeWidget(propertyWidget_);
        delete propertyWidget_;
    }
}

void KeyframeEditorWidget::onKeyframeTimeChanged(Keyframe* key, Seconds oldTime) {
    timeSpinner_->setValue(key->getTime().count());
    sequenceEditorWidget_->setReorderNeeded();
}

void KeyframeEditorWidget::onKeyframeSelectionChanged(Keyframe *key) {
    sequenceEditorWidget_->updateVisibility();
}

}  // namespace animation

}  // namespace inviwo
<commit_msg>AnimationQT: Added comment on why we need to manually remove and delete the propertyWidget_<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2017 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. 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.
 *
 * 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 <modules/animationqt/sequenceeditorpanel/keyframeeditorwidget.h>
#include <modules/animationqt/sequenceeditorpanel/sequenceeditorwidget.h>
#include <modules/animation/datastructures/propertytrack.h>
#include <modules/animation/datastructures/controltrack.h>

#include <modules/qtwidgets/properties/ordinalpropertywidgetqt.h>

#include <inviwo/core/properties/property.h>
#include <inviwo/core/properties/propertywidgetfactory.h>

#include <warn/push>
#include <warn/ignore/all>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QDoubleSpinBox>
#include <QComboBox>
#include <warn/pop>

namespace inviwo {

namespace animation {
KeyframeEditorWidget::KeyframeEditorWidget(Keyframe &keyframe, SequenceEditorWidget *parent)
    : QWidget(parent), keyframe_(keyframe), sequenceEditorWidget_(parent) {

    setObjectName("KeyframeEditorWidget");

    keyframe.addObserver(this);

    layout_ = new QHBoxLayout();

    timeSpinner_ = new QDoubleSpinBox();
    timeSpinner_->setValue(keyframe.getTime().count());
    timeSpinner_->setSuffix("s");
    timeSpinner_->setSingleStep(0.1);
    timeSpinner_->setDecimals(5);

    void (QDoubleSpinBox::*signal)(double) = &QDoubleSpinBox::valueChanged;
    connect(timeSpinner_, signal, this, [this](double t) { keyframe_.setTime(Seconds(t)); });

    layout_->addWidget(timeSpinner_);

    if (auto propTrack = dynamic_cast<BasePropertyTrack *>(&parent->getTrack())) {
        auto baseProperty = propTrack->getProperty();
        property_.reset(baseProperty->clone());
        propTrack->setOtherProperty(property_.get(), &keyframe);
        property_->onChange(
            [ b = baseProperty, p = property_.get(), t = propTrack, k = &keyframe_ ]() {
                b->set(p);
                t->updateKeyframeFromProperty(p, k);
            });
        property_->setOwner(nullptr);

        auto propWidget =
            util::getInviwoApplication()->getPropertyWidgetFactory()->create(property_.get());
        propertyWidget_ = static_cast<PropertyWidgetQt *>(propWidget.release());

        if (auto label = propertyWidget_->findChild<EditableLabelQt *>()) {
            label->setVisible(false);
        }

        layout_->addWidget(propertyWidget_);
    } else if (auto ctrlTrack = dynamic_cast<ControlTrack *>(&parent->getTrack())) {
        // Assume that we only have ControlKeyframes within ControlTracks
        auto &ctrlKey = *static_cast<ControlKeyframe *>(&keyframe);

        actionWidget_ = new QComboBox();
        actionWidget_->addItems({"Pause", "Jump To", "Script"});
        actionWidget_->setCurrentIndex(static_cast<int>(ctrlKey.getAction()));

        jumpToWidget_ = new QDoubleSpinBox();
        jumpToWidget_->setValue(ctrlKey.getPayload().jumpToTime.count());
        jumpToWidget_->setSuffix("s");
        jumpToWidget_->setSingleStep(0.1);
        jumpToWidget_->setDecimals(5);
        jumpToWidget_->setVisible(ctrlKey.getAction() == ControlAction::JumpTo);

        connect(actionWidget_, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated),
                [this, &ctrlKey](int idx) {
                    ctrlKey.setAction(static_cast<ControlAction>(idx));
                    jumpToWidget_->setVisible(ctrlKey.getAction() == ControlAction::JumpTo);
                });

        connect(timeSpinner_,
                static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this,
                [this, &ctrlKey](double t) {
                    ControlPayload payload;
                    payload.jumpToTime = Seconds{t};
                    ctrlKey.setPayload(payload);
                });

        layout_->addWidget(actionWidget_);
        layout_->addWidget(jumpToWidget_);
    }

    setLayout(layout_);
}

KeyframeEditorWidget::~KeyframeEditorWidget() {
    if (propertyWidget_) {
        // We need to manually remove and delete the propertyWidget_ since the destructor of
        // propertyWidget_ tries to use the property. If we do not remove it it will be destroyed in
        // QWidgets destructor which is called after this destructor, hence, the property has been
        // destroyed.
        layout_->removeWidget(propertyWidget_);
        delete propertyWidget_;
    }
}

void KeyframeEditorWidget::onKeyframeTimeChanged(Keyframe *key, Seconds oldTime) {
    timeSpinner_->setValue(key->getTime().count());
    sequenceEditorWidget_->setReorderNeeded();
}

void KeyframeEditorWidget::onKeyframeSelectionChanged(Keyframe *key) {
    sequenceEditorWidget_->updateVisibility();
}

}  // namespace animation

}  // namespace inviwo
<|endoftext|>


<commit_before>/*****************************************************************************
 * customwidgets.cpp: Custom widgets
 ****************************************************************************
 * Copyright (C) 2006 the VideoLAN team
 * Copyright (C) 2004 Daniel Molkentin <molkentin@kde.org>
 * $Id: qvlcframe.hpp 16283 2006-08-17 18:16:09Z zorglub $
 *
 * Authors: Clément Stenac <zorglub@videolan.org>
 * The "ClickLineEdit" control is based on code by  Daniel Molkentin
 * <molkentin@kde.org> for libkdepim
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/

#include "customwidgets.hpp"
#include <QPainter>
#include <QLineEdit>
#include <QPainter>
#include <QColorGroup>
#include <QRect>
#include <QKeyEvent>
#include <QWheelEvent>

#include <vlc_keys.h>

ClickLineEdit::ClickLineEdit( const QString &msg, QWidget *parent) : QLineEdit( parent )
{
    mDrawClickMsg = true;
    setClickMessage( msg );
}

void ClickLineEdit::setClickMessage( const QString &msg )
{
    mClickMessage = msg;
    repaint();
}

void ClickLineEdit::setText( const QString &txt )
{
    mDrawClickMsg = txt.isEmpty();
    repaint();
    QLineEdit::setText( txt );
}

void ClickLineEdit::paintEvent( QPaintEvent *pe )
{
    QPainter p( this );
    QLineEdit::paintEvent( pe );
    if ( mDrawClickMsg == true && !hasFocus() ) {
        QPen tmp = p.pen();
        p.setPen( palette().color( QPalette::Disabled, QPalette::Text ) );
        QRect cr = contentsRect();
        // Add two pixel margin on the left side
        cr.setLeft( cr.left() + 3 );
        p.drawText( cr, Qt::AlignLeft | Qt::AlignVCenter, mClickMessage );
        p.setPen( tmp );
    }
}

void ClickLineEdit::dropEvent( QDropEvent *ev )
{
    mDrawClickMsg = false;
    QLineEdit::dropEvent( ev );
}

void ClickLineEdit::focusInEvent( QFocusEvent *ev )
{
    if ( mDrawClickMsg == true ) {
        mDrawClickMsg = false;
        repaint();
    }
    QLineEdit::focusInEvent( ev );
}

void ClickLineEdit::focusOutEvent( QFocusEvent *ev )
{
    if ( text().isEmpty() ) {
        mDrawClickMsg = true;
        repaint();
    }
    QLineEdit::focusOutEvent( ev );
}

/***************************************************************************
 * Hotkeys converters
 ***************************************************************************/
int qtKeyModifiersToVLC( QInputEvent* e )
{
    int i_keyModifiers = 0;
    if( e->modifiers() & Qt::ShiftModifier ) i_keyModifiers |= KEY_MODIFIER_SHIFT;
    if( e->modifiers() & Qt::AltModifier ) i_keyModifiers |= KEY_MODIFIER_ALT;
    if( e->modifiers() & Qt::ControlModifier ) i_keyModifiers |= KEY_MODIFIER_CTRL;
    if( e->modifiers() & Qt::MetaModifier ) i_keyModifiers |= KEY_MODIFIER_META;
    return i_keyModifiers;
}

int qtEventToVLCKey( QKeyEvent *e )
{
    int i_vlck = 0;
    /* Handle modifiers */
    i_vlck |= qtKeyModifiersToVLC( e );

    bool found = false;
    /* Look for some special keys */
#define HANDLE( qt, vk ) case Qt::qt : i_vlck |= vk; found = true;break
    switch( e->key() )
    {
        HANDLE( Key_Left, KEY_LEFT );
        HANDLE( Key_Right, KEY_RIGHT );
        HANDLE( Key_Up, KEY_UP );
        HANDLE( Key_Down, KEY_DOWN );
        HANDLE( Key_Space, KEY_SPACE );
        HANDLE( Key_Escape, KEY_ESC );
        HANDLE( Key_Enter, KEY_ENTER );
        HANDLE( Key_F1, KEY_F1 );
        HANDLE( Key_F2, KEY_F2 );
        HANDLE( Key_F3, KEY_F3 );
        HANDLE( Key_F4, KEY_F4 );
        HANDLE( Key_F5, KEY_F5 );
        HANDLE( Key_F6, KEY_F6 );
        HANDLE( Key_F7, KEY_F7 );
        HANDLE( Key_F8, KEY_F8 );
        HANDLE( Key_F9, KEY_F9 );
        HANDLE( Key_F10, KEY_F10 );
        HANDLE( Key_F11, KEY_F11 );
        HANDLE( Key_F12, KEY_F12 );
        HANDLE( Key_PageUp, KEY_PAGEUP );
        HANDLE( Key_PageDown, KEY_PAGEDOWN );
        HANDLE( Key_Home, KEY_HOME );
        HANDLE( Key_End, KEY_END );
        HANDLE( Key_Insert, KEY_INSERT );
        HANDLE( Key_Delete, KEY_DELETE );

    }
    if( !found )
    {
        /* Force lowercase */
        if( e->key() >= Qt::Key_A && e->key() <= Qt::Key_Z )
            i_vlck += e->key() + 32;
        /* Rest of the ascii range */
        else if( e->key() >= Qt::Key_Space && e->key() <= Qt::Key_AsciiTilde )
            i_vlck += e->key();
    }
    return i_vlck;
}

int qtWheelEventToVLCKey( QWheelEvent *e )
{
    int i_vlck = 0;
    /* Handle modifiers */
    i_vlck |= qtKeyModifiersToVLC( e );
    if ( e->delta() > 0 )
        i_vlck |= KEY_MOUSEWHEELUP;
    else
        i_vlck |= KEY_MOUSEWHEELDOWN;
    return i_vlck;
}

QString VLCKeyToString( int val )
{
    QString r = "";
    if( val & KEY_MODIFIER_CTRL )
        r+= "Ctrl+";
    if( val & KEY_MODIFIER_ALT )
        r+= "Alt+";
    if( val & KEY_MODIFIER_SHIFT )
        r+= "Shift+";

    unsigned int i_keys = sizeof(vlc_keys)/sizeof(key_descriptor_t);
    for( unsigned int i = 0; i< i_keys; i++ )
    {
        if( vlc_keys[i].i_key_code == (val& ~KEY_MODIFIER) )
        {
            r+= vlc_keys[i].psz_key_string;
        }
    }
    return r;
}
<commit_msg>Qt4 - MediaKeys support, patch by Ilkka Ollakka<commit_after>/*****************************************************************************
 * customwidgets.cpp: Custom widgets
 ****************************************************************************
 * Copyright (C) 2006 the VideoLAN team
 * Copyright (C) 2004 Daniel Molkentin <molkentin@kde.org>
 * $Id: qvlcframe.hpp 16283 2006-08-17 18:16:09Z zorglub $
 *
 * Authors: Clément Stenac <zorglub@videolan.org>
 * The "ClickLineEdit" control is based on code by  Daniel Molkentin
 * <molkentin@kde.org> for libkdepim
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/

#include "customwidgets.hpp"
#include <QPainter>
#include <QLineEdit>
#include <QPainter>
#include <QColorGroup>
#include <QRect>
#include <QKeyEvent>
#include <QWheelEvent>

#include <vlc_keys.h>

ClickLineEdit::ClickLineEdit( const QString &msg, QWidget *parent) : QLineEdit( parent )
{
    mDrawClickMsg = true;
    setClickMessage( msg );
}

void ClickLineEdit::setClickMessage( const QString &msg )
{
    mClickMessage = msg;
    repaint();
}

void ClickLineEdit::setText( const QString &txt )
{
    mDrawClickMsg = txt.isEmpty();
    repaint();
    QLineEdit::setText( txt );
}

void ClickLineEdit::paintEvent( QPaintEvent *pe )
{
    QPainter p( this );
    QLineEdit::paintEvent( pe );
    if ( mDrawClickMsg == true && !hasFocus() ) {
        QPen tmp = p.pen();
        p.setPen( palette().color( QPalette::Disabled, QPalette::Text ) );
        QRect cr = contentsRect();
        // Add two pixel margin on the left side
        cr.setLeft( cr.left() + 3 );
        p.drawText( cr, Qt::AlignLeft | Qt::AlignVCenter, mClickMessage );
        p.setPen( tmp );
    }
}

void ClickLineEdit::dropEvent( QDropEvent *ev )
{
    mDrawClickMsg = false;
    QLineEdit::dropEvent( ev );
}

void ClickLineEdit::focusInEvent( QFocusEvent *ev )
{
    if ( mDrawClickMsg == true ) {
        mDrawClickMsg = false;
        repaint();
    }
    QLineEdit::focusInEvent( ev );
}

void ClickLineEdit::focusOutEvent( QFocusEvent *ev )
{
    if ( text().isEmpty() ) {
        mDrawClickMsg = true;
        repaint();
    }
    QLineEdit::focusOutEvent( ev );
}

/***************************************************************************
 * Hotkeys converters
 ***************************************************************************/
int qtKeyModifiersToVLC( QInputEvent* e )
{
    int i_keyModifiers = 0;
    if( e->modifiers() & Qt::ShiftModifier ) i_keyModifiers |= KEY_MODIFIER_SHIFT;
    if( e->modifiers() & Qt::AltModifier ) i_keyModifiers |= KEY_MODIFIER_ALT;
    if( e->modifiers() & Qt::ControlModifier ) i_keyModifiers |= KEY_MODIFIER_CTRL;
    if( e->modifiers() & Qt::MetaModifier ) i_keyModifiers |= KEY_MODIFIER_META;
    return i_keyModifiers;
}

int qtEventToVLCKey( QKeyEvent *e )
{
    int i_vlck = 0;
    /* Handle modifiers */
    i_vlck |= qtKeyModifiersToVLC( e );

    bool found = false;
    /* Look for some special keys */
#define HANDLE( qt, vk ) case Qt::qt : i_vlck |= vk; found = true;break
    switch( e->key() )
    {
        HANDLE( Key_Left, KEY_LEFT );
        HANDLE( Key_Right, KEY_RIGHT );
        HANDLE( Key_Up, KEY_UP );
        HANDLE( Key_Down, KEY_DOWN );
        HANDLE( Key_Space, KEY_SPACE );
        HANDLE( Key_Escape, KEY_ESC );
        HANDLE( Key_Enter, KEY_ENTER );
        HANDLE( Key_F1, KEY_F1 );
        HANDLE( Key_F2, KEY_F2 );
        HANDLE( Key_F3, KEY_F3 );
        HANDLE( Key_F4, KEY_F4 );
        HANDLE( Key_F5, KEY_F5 );
        HANDLE( Key_F6, KEY_F6 );
        HANDLE( Key_F7, KEY_F7 );
        HANDLE( Key_F8, KEY_F8 );
        HANDLE( Key_F9, KEY_F9 );
        HANDLE( Key_F10, KEY_F10 );
        HANDLE( Key_F11, KEY_F11 );
        HANDLE( Key_F12, KEY_F12 );
        HANDLE( Key_PageUp, KEY_PAGEUP );
        HANDLE( Key_PageDown, KEY_PAGEDOWN );
        HANDLE( Key_Home, KEY_HOME );
        HANDLE( Key_End, KEY_END );
        HANDLE( Key_Insert, KEY_INSERT );
        HANDLE( Key_Delete, KEY_DELETE );
        HANDLE( Key_VolumeDown, KEY_VOLUME_DOWN);
        HANDLE( Key_VolumeUp, KEY_VOLUME_UP );
        HANDLE( Key_MediaPlay, KEY_MEDIA_PLAY_PAUSE );
        HANDLE( Key_MediaStop, KEY_MEDIA_STOP );
        HANDLE( Key_MediaPrevious, KEY_MEDIA_PREV_TRACK );
        HANDLE( Key_MediaNext, KEY_MEDIA_NEXT_TRACK );

    }
    if( !found )
    {
        /* Force lowercase */
        if( e->key() >= Qt::Key_A && e->key() <= Qt::Key_Z )
            i_vlck += e->key() + 32;
        /* Rest of the ascii range */
        else if( e->key() >= Qt::Key_Space && e->key() <= Qt::Key_AsciiTilde )
            i_vlck += e->key();
    }
    return i_vlck;
}

int qtWheelEventToVLCKey( QWheelEvent *e )
{
    int i_vlck = 0;
    /* Handle modifiers */
    i_vlck |= qtKeyModifiersToVLC( e );
    if ( e->delta() > 0 )
        i_vlck |= KEY_MOUSEWHEELUP;
    else
        i_vlck |= KEY_MOUSEWHEELDOWN;
    return i_vlck;
}

QString VLCKeyToString( int val )
{
    QString r = "";
    if( val & KEY_MODIFIER_CTRL )
        r+= "Ctrl+";
    if( val & KEY_MODIFIER_ALT )
        r+= "Alt+";
    if( val & KEY_MODIFIER_SHIFT )
        r+= "Shift+";

    unsigned int i_keys = sizeof(vlc_keys)/sizeof(key_descriptor_t);
    for( unsigned int i = 0; i< i_keys; i++ )
    {
        if( vlc_keys[i].i_key_code == (val& ~KEY_MODIFIER) )
        {
            r+= vlc_keys[i].psz_key_string;
        }
    }
    return r;
}
<|endoftext|>