<commit_before>/*
 * Copyright (c) 2012 ARM Limited
 * All rights reserved.
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2006 The Regents of The University of Michigan
 * 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 copyright holders 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.
 *
 * Authors: Ali Saidi
 *          Andreas Hansson
 */

#include "debug/Drain.hh"
#include "debug/PacketQueue.hh"
#include "mem/packet_queue.hh"

using namespace std;

PacketQueue::PacketQueue(EventManager& _em, const std::string& _label)
    : em(_em), sendEvent(this), drainEvent(NULL), label(_label),
      waitingOnRetry(false)
{
}

PacketQueue::~PacketQueue()
{
}

void
PacketQueue::retry()
{
    DPRINTF(PacketQueue, "Queue %s received retry\n", name());
    assert(waitingOnRetry);
    sendDeferredPacket();
}

bool
PacketQueue::checkFunctional(PacketPtr pkt)
{
    pkt->pushLabel(label);

    DeferredPacketIterator i = transmitList.begin();
    DeferredPacketIterator end = transmitList.end();
    bool found = false;

    while (!found && i != end) {
        // If the buffered packet contains data, and it overlaps the
        // current packet, then update data
        found = pkt->checkFunctional(i->pkt);
        ++i;
    }

    pkt->popLabel();

    return found;
}

void
PacketQueue::schedSendEvent(Tick when)
{
    // if we are waiting on a retry, do not schedule a send event, and
    // instead rely on retry being called
    if (waitingOnRetry) {
        assert(!sendEvent.scheduled());
        return;
    }

    if (!sendEvent.scheduled()) {
        em.schedule(&sendEvent, when);
    } else if (sendEvent.when() > when) {
        em.reschedule(&sendEvent, when);
    }
}

void
PacketQueue::schedSendTiming(PacketPtr pkt, Tick when, bool send_as_snoop)
{
    assert(when > curTick());

    // nothing on the list, or earlier than current front element,
    // schedule an event
    if (transmitList.empty() || when < transmitList.front().tick) {
        // note that currently we ignore a potentially outstanding retry
        // and could in theory put a new packet at the head of the
        // transmit list before retrying the existing packet
        transmitList.push_front(DeferredPacket(when, pkt, send_as_snoop));
        schedSendEvent(when);
        return;
    }

    // list is non-empty and this belongs at the end
    if (when >= transmitList.back().tick) {
        transmitList.push_back(DeferredPacket(when, pkt, send_as_snoop));
        return;
    }

    // this belongs in the middle somewhere, insertion sort
    DeferredPacketIterator i = transmitList.begin();
    ++i; // already checked for insertion at front
    while (i != transmitList.end() && when >= i->tick)
        ++i;
    transmitList.insert(i, DeferredPacket(when, pkt, send_as_snoop));
}

void PacketQueue::trySendTiming()
{
    assert(deferredPacketReady());

    // take the next packet off the list here, as we might return to
    // ourselves through the sendTiming call below
    DeferredPacket dp = transmitList.front();
    transmitList.pop_front();

    // use the appropriate implementation of sendTiming based on the
    // type of port associated with the queue, and whether the packet
    // is to be sent as a snoop or not
    waitingOnRetry = !sendTiming(dp.pkt, dp.sendAsSnoop);

    if (waitingOnRetry) {
        // put the packet back at the front of the list (packet should
        // not have changed since it wasn't accepted)
        assert(!sendEvent.scheduled());
        transmitList.push_front(dp);
    }
}

void
PacketQueue::scheduleSend(Tick time)
{
    // the next ready time is either determined by the next deferred packet,
    // or in the cache through the MSHR ready time
    Tick nextReady = std::min(deferredPacketReadyTime(), time);

    if (nextReady != MaxTick) {
        // if the sendTiming caused someone else to call our
        // recvTiming we could already have an event scheduled, check
        if (!sendEvent.scheduled())
            em.schedule(&sendEvent, std::max(nextReady, curTick() + 1));
    } else {
        // no more to send, so if we're draining, we may be done
        if (drainEvent && transmitList.empty() && !sendEvent.scheduled()) {
            DPRINTF(Drain, "PacketQueue done draining,"
                    "processing drain event\n");
            drainEvent->process();
            drainEvent = NULL;
        }
    }
}

void
PacketQueue::sendDeferredPacket()
{
    // try to send what is on the list, this will set waitingOnRetry
    // accordingly
    trySendTiming();

    // if we succeeded and are not waiting for a retry, schedule the
    // next send
    if (!waitingOnRetry) {
        scheduleSend();
    }
}

void
PacketQueue::processSendEvent()
{
    assert(!waitingOnRetry);
    sendDeferredPacket();
}

unsigned int
PacketQueue::drain(Event *de)
{
    if (transmitList.empty() && !sendEvent.scheduled())
        return 0;
    DPRINTF(Drain, "PacketQueue not drained\n");
    drainEvent = de;
    return 1;
}

MasterPacketQueue::MasterPacketQueue(EventManager& _em, MasterPort& _masterPort,
                                     const std::string _label)
    : PacketQueue(_em, _label), masterPort(_masterPort)
{
}

bool
MasterPacketQueue::sendTiming(PacketPtr pkt, bool send_as_snoop)
{
    // attempt to send the packet and return according to the outcome
    if (!send_as_snoop)
        return masterPort.sendTimingReq(pkt);
    else
        return masterPort.sendTimingSnoopResp(pkt);
}

SlavePacketQueue::SlavePacketQueue(EventManager& _em, SlavePort& _slavePort,
                                   const std::string _label)
    : PacketQueue(_em, _label), slavePort(_slavePort)
{
}

bool
SlavePacketQueue::sendTiming(PacketPtr pkt, bool send_as_snoop)
{
    // we should never have queued snoop requests
    assert(!send_as_snoop);
    return slavePort.sendTimingResp(pkt);
}
<commit_msg>PacketQueue: Allow queuing in the same tick as desired send tick<commit_after>/*
 * Copyright (c) 2012 ARM Limited
 * All rights reserved.
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2006 The Regents of The University of Michigan
 * 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 copyright holders 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.
 *
 * Authors: Ali Saidi
 *          Andreas Hansson
 */

#include "debug/Drain.hh"
#include "debug/PacketQueue.hh"
#include "mem/packet_queue.hh"

using namespace std;

PacketQueue::PacketQueue(EventManager& _em, const std::string& _label)
    : em(_em), sendEvent(this), drainEvent(NULL), label(_label),
      waitingOnRetry(false)
{
}

PacketQueue::~PacketQueue()
{
}

void
PacketQueue::retry()
{
    DPRINTF(PacketQueue, "Queue %s received retry\n", name());
    assert(waitingOnRetry);
    sendDeferredPacket();
}

bool
PacketQueue::checkFunctional(PacketPtr pkt)
{
    pkt->pushLabel(label);

    DeferredPacketIterator i = transmitList.begin();
    DeferredPacketIterator end = transmitList.end();
    bool found = false;

    while (!found && i != end) {
        // If the buffered packet contains data, and it overlaps the
        // current packet, then update data
        found = pkt->checkFunctional(i->pkt);
        ++i;
    }

    pkt->popLabel();

    return found;
}

void
PacketQueue::schedSendEvent(Tick when)
{
    // if we are waiting on a retry, do not schedule a send event, and
    // instead rely on retry being called
    if (waitingOnRetry) {
        assert(!sendEvent.scheduled());
        return;
    }

    if (!sendEvent.scheduled()) {
        em.schedule(&sendEvent, when);
    } else if (sendEvent.when() > when) {
        em.reschedule(&sendEvent, when);
    }
}

void
PacketQueue::schedSendTiming(PacketPtr pkt, Tick when, bool send_as_snoop)
{
    // we can still send a packet before the end of this tick
    assert(when >= curTick());

    // nothing on the list, or earlier than current front element,
    // schedule an event
    if (transmitList.empty() || when < transmitList.front().tick) {
        // note that currently we ignore a potentially outstanding retry
        // and could in theory put a new packet at the head of the
        // transmit list before retrying the existing packet
        transmitList.push_front(DeferredPacket(when, pkt, send_as_snoop));
        schedSendEvent(when);
        return;
    }

    // list is non-empty and this belongs at the end
    if (when >= transmitList.back().tick) {
        transmitList.push_back(DeferredPacket(when, pkt, send_as_snoop));
        return;
    }

    // this belongs in the middle somewhere, insertion sort
    DeferredPacketIterator i = transmitList.begin();
    ++i; // already checked for insertion at front
    while (i != transmitList.end() && when >= i->tick)
        ++i;
    transmitList.insert(i, DeferredPacket(when, pkt, send_as_snoop));
}

void PacketQueue::trySendTiming()
{
    assert(deferredPacketReady());

    // take the next packet off the list here, as we might return to
    // ourselves through the sendTiming call below
    DeferredPacket dp = transmitList.front();
    transmitList.pop_front();

    // use the appropriate implementation of sendTiming based on the
    // type of port associated with the queue, and whether the packet
    // is to be sent as a snoop or not
    waitingOnRetry = !sendTiming(dp.pkt, dp.sendAsSnoop);

    if (waitingOnRetry) {
        // put the packet back at the front of the list (packet should
        // not have changed since it wasn't accepted)
        assert(!sendEvent.scheduled());
        transmitList.push_front(dp);
    }
}

void
PacketQueue::scheduleSend(Tick time)
{
    // the next ready time is either determined by the next deferred packet,
    // or in the cache through the MSHR ready time
    Tick nextReady = std::min(deferredPacketReadyTime(), time);

    if (nextReady != MaxTick) {
        // if the sendTiming caused someone else to call our
        // recvTiming we could already have an event scheduled, check
        if (!sendEvent.scheduled())
            em.schedule(&sendEvent, std::max(nextReady, curTick() + 1));
    } else {
        // no more to send, so if we're draining, we may be done
        if (drainEvent && transmitList.empty() && !sendEvent.scheduled()) {
            DPRINTF(Drain, "PacketQueue done draining,"
                    "processing drain event\n");
            drainEvent->process();
            drainEvent = NULL;
        }
    }
}

void
PacketQueue::sendDeferredPacket()
{
    // try to send what is on the list, this will set waitingOnRetry
    // accordingly
    trySendTiming();

    // if we succeeded and are not waiting for a retry, schedule the
    // next send
    if (!waitingOnRetry) {
        scheduleSend();
    }
}

void
PacketQueue::processSendEvent()
{
    assert(!waitingOnRetry);
    sendDeferredPacket();
}

unsigned int
PacketQueue::drain(Event *de)
{
    if (transmitList.empty() && !sendEvent.scheduled())
        return 0;
    DPRINTF(Drain, "PacketQueue not drained\n");
    drainEvent = de;
    return 1;
}

MasterPacketQueue::MasterPacketQueue(EventManager& _em, MasterPort& _masterPort,
                                     const std::string _label)
    : PacketQueue(_em, _label), masterPort(_masterPort)
{
}

bool
MasterPacketQueue::sendTiming(PacketPtr pkt, bool send_as_snoop)
{
    // attempt to send the packet and return according to the outcome
    if (!send_as_snoop)
        return masterPort.sendTimingReq(pkt);
    else
        return masterPort.sendTimingSnoopResp(pkt);
}

SlavePacketQueue::SlavePacketQueue(EventManager& _em, SlavePort& _slavePort,
                                   const std::string _label)
    : PacketQueue(_em, _label), slavePort(_slavePort)
{
}

bool
SlavePacketQueue::sendTiming(PacketPtr pkt, bool send_as_snoop)
{
    // we should never have queued snoop requests
    assert(!send_as_snoop);
    return slavePort.sendTimingResp(pkt);
}
<|endoftext|>


<commit_before><commit_msg>legion: another small fix for remote copy select sources<commit_after><|endoftext|>


<commit_before>#include "types.h"
#include "atomic.hh"
#include "spinlock.h"
#include "kernel.hh"
#include "cpputil.hh"
#include "radix.hh"

template<class CB>
void
descend(u64 key, markptr<void> *n, u32 level, CB cb)
{
  // for now, we only support exact multiples of bits_per_level
  assert(key_bits == bits_per_level * radix_levels);
  assert(n);

  void *v = n->ptr();
  if (v == 0) {
    radix_node *new_rn = new radix_node();
    if (n->ptr().cmpxch_update(&v, (void*) new_rn))
      v = new_rn;
    else
      delete new_rn;
  }

  radix_node *rn = (radix_node*) v;

  u64 idx = key >> (bits_per_level * level);
  idx &= (1<<bits_per_level)-1;
  markptr<void> *vptr = &rn->ptr[idx];
  if (level == 0)
    cb(vptr);
  else
    descend(key, vptr, level-1, cb);
}

radix_elem*
radix::search(u64 key)
{
  radix_elem *result = 0;
  descend(key >> shift_, &root_, radix_levels-1, [&result](markptr<void> *v) {
      result = (radix_elem*) v->ptr().load();
    });
  return result;
}

radix_range
radix::search_lock(u64 start, u64 size)
{
  return radix_range(this, start >> shift_, size >> shift_);
}

radix_range::radix_range(radix *r, u64 start, u64 size)
  : r_(r), start_(start), size_(size)
{
  for (u64 k = start_; k != start_ + size_; k++)
    descend(k, &r_->root_, radix_levels-1, [](markptr<void> *v) {
        while (!v->mark().xchg(true))
          ; // spin
      });
}

radix_range::~radix_range()
{
  if (!r_)
    return;

  for (u64 k = start_; k != start_ + size_; k++)
    descend(k, &r_->root_, radix_levels-1, [](markptr<void> *v) {
        v->mark() = false;
      });
}

void
radix_range::replace(u64 start, u64 size, radix_elem *val)
{
  start = start >> r_->shift_;
  size = size >> r_->shift_;

  assert(start >= start_);
  assert(start + size <= start_ + size_);

  for (u64 k = start; k != start + size; k++)
    descend(k, &r_->root_, radix_levels-1, [val](markptr<void> *v) {
        void* cur = v->ptr().load();
        while (!v->ptr().cmpxch_update(&cur, val))
          ; // spin
        val->incref();
        if (cur)
          ((radix_elem*) cur)->decref();
      });
}

radix_elem*
radix_iterator::operator*()
{
  radix_elem *result = 0;
  descend(k_, (markptr<void>*) &r_->root_, radix_levels-1, [&result](markptr<void> *v) {
      result = (radix_elem*) v->ptr().load();
    });
  return result;
}
<commit_msg>Make the key_bits multiple assertion a static_assert<commit_after>#include "types.h"
#include "atomic.hh"
#include "spinlock.h"
#include "kernel.hh"
#include "cpputil.hh"
#include "radix.hh"

template<class CB>
void
descend(u64 key, markptr<void> *n, u32 level, CB cb)
{
  static_assert(key_bits == bits_per_level * radix_levels,
                "for now, we only support exact multiples of bits_per_level");
  assert(n);

  void *v = n->ptr();
  if (v == 0) {
    radix_node *new_rn = new radix_node();
    if (n->ptr().cmpxch_update(&v, (void*) new_rn))
      v = new_rn;
    else
      delete new_rn;
  }

  radix_node *rn = (radix_node*) v;

  u64 idx = key >> (bits_per_level * level);
  idx &= (1<<bits_per_level)-1;
  markptr<void> *vptr = &rn->ptr[idx];
  if (level == 0)
    cb(vptr);
  else
    descend(key, vptr, level-1, cb);
}

radix_elem*
radix::search(u64 key)
{
  radix_elem *result = 0;
  descend(key >> shift_, &root_, radix_levels-1, [&result](markptr<void> *v) {
      result = (radix_elem*) v->ptr().load();
    });
  return result;
}

radix_range
radix::search_lock(u64 start, u64 size)
{
  return radix_range(this, start >> shift_, size >> shift_);
}

radix_range::radix_range(radix *r, u64 start, u64 size)
  : r_(r), start_(start), size_(size)
{
  for (u64 k = start_; k != start_ + size_; k++)
    descend(k, &r_->root_, radix_levels-1, [](markptr<void> *v) {
        while (!v->mark().xchg(true))
          ; // spin
      });
}

radix_range::~radix_range()
{
  if (!r_)
    return;

  for (u64 k = start_; k != start_ + size_; k++)
    descend(k, &r_->root_, radix_levels-1, [](markptr<void> *v) {
        v->mark() = false;
      });
}

void
radix_range::replace(u64 start, u64 size, radix_elem *val)
{
  start = start >> r_->shift_;
  size = size >> r_->shift_;

  assert(start >= start_);
  assert(start + size <= start_ + size_);

  for (u64 k = start; k != start + size; k++)
    descend(k, &r_->root_, radix_levels-1, [val](markptr<void> *v) {
        void* cur = v->ptr().load();
        while (!v->ptr().cmpxch_update(&cur, val))
          ; // spin
        val->incref();
        if (cur)
          ((radix_elem*) cur)->decref();
      });
}

radix_elem*
radix_iterator::operator*()
{
  radix_elem *result = 0;
  descend(k_, (markptr<void>*) &r_->root_, radix_levels-1, [&result](markptr<void> *v) {
      result = (radix_elem*) v->ptr().load();
    });
  return result;
}
<|endoftext|>


<commit_before>/*************** <auto-copyright.pl BEGIN do not edit this line> **************
 *
 * VR Juggler is (C) Copyright 1998-2003 by Iowa State University
 *
 * Original Authors:
 *   Allen Bierbaum, Christopher Just,
 *   Patrick Hartling, Kevin Meinert,
 *   Carolina Cruz-Neira, Albert Baker
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 * -----------------------------------------------------------------
 * File:          $RCSfile$
 * Date modified: $Date$
 * Version:       $Revision$
 * -----------------------------------------------------------------
 *
 *************** <auto-copyright.pl END do not edit this line> ***************/

#include <gadget/Devices/DriverConfig.h>
#include <vpr/Util/Debug.h>
#include <jccl/Config/ConfigElement.h>
#include <gadget/Type/DeviceConstructor.h>
#include <gadget/Util/Debug.h>

#include <drivers/Open/LinuxJoydev/LinuxJoydev.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <fcntl.h>

#include <linux/joystick.h>      // Get the joystick abilities

extern "C"
{

GADGET_DRIVER_EXPORT(void) initDevice(gadget::InputManager* inputMgr)
{
   new gadget::DeviceConstructor<gadget::LinuxJoydev>(inputMgr);
}

}

namespace gadget
{

/** Constructor. */
LinuxJoydev::LinuxJoydev()
{;}

/**
 * Destructor.
 *
 * @pre None.
 * @post Shared memory is released.
 */
LinuxJoydev::~LinuxJoydev()
{
}

std::string LinuxJoydev::getElementType()
{
   return "linux_joydev";
}

/**
 *
 */
bool LinuxJoydev::config(jccl::ConfigElementPtr e)
{
   if(! (Input::config(e) && Digital::config(e) && Analog::config(e)))
   {
      return false;
   }

   mJsLabel = e->getName();
   mPortName = e->getProperty<std::string>("port_name");

   unsigned num_axis_buttons = e->getNum("axis_buttons");
   for(unsigned i=0;i<num_axis_buttons;++i)
   {
      unsigned idx = e->getProperty<int>("axis_buttons", i);
      mAxisButtonIndices.push_back(idx);
   }

   return true;
}

/** Begin sampling.
* Connect to the joystick and prepare to read.
*/
bool LinuxJoydev::startSampling()
{
   vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CONFIG_STATUS_LVL) << "Opening Linux Joystick driver on port: " << mPortName << std::endl << vprDEBUG_FLUSH;

   mJsFD = open(mPortName.c_str(), O_RDONLY | O_NONBLOCK);   // Open the joystick non-blocking

   if(mJsFD < 0)
   {
      vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CRITICAL_LVL) << "ERROR: Failed to open Linux Joystick: " << mPortName << std::endl << vprDEBUG_FLUSH;
      return false;
   }

   // Read in the settings
   int version;
   unsigned char num_axes, num_buttons;
   char js_name[255];

   ioctl(mJsFD, JSIOCGVERSION, &version);
   ioctl(mJsFD, JSIOCGAXES, &num_axes);
   ioctl(mJsFD, JSIOCGBUTTONS, &num_buttons);

   mNumAxes = num_axes;
   mNumButtons = num_buttons;

   // Get joystick name
   if (ioctl(mJsFD, JSIOCGNAME(sizeof(js_name)), js_name) < 0)
   {  mPhysicalJsName = std::string("Unknown"); }
   else
   {  mPhysicalJsName = js_name; }

   // Output joystick description
   vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CONFIG_STATUS_LVL)
         << "  joystick label: " << mJsLabel << std::endl
         << "   joystick name: " << mPhysicalJsName << std::endl
         << "            axes: " << mNumAxes << std::endl
         << "         buttons: " << mNumButtons << std::endl
         << "      driver ver: " << version << std::endl
         << "    axis buttons: ";

   for(unsigned i=0;i<mAxisButtonIndices.size(); ++i)
   { vprDEBUG_CONTnl(gadgetDBG_INPUT_MGR, vprDBG_CONFIG_STATUS_LVL) << mAxisButtonIndices[i] << " "; }
   vprDEBUG_CONTnl(gadgetDBG_INPUT_MGR, vprDBG_CONFIG_STATUS_LVL) << std::endl << vprDEBUG_FLUSH;

   // Allocate initial device data
   // - By default this will clear them out
   mCurAxes.resize(mNumAxes);
   mCurAxesRanges.resize(mNumAxes, axis_range_t(0.0f, 255.0f));             // Initialize ranges to 0,255
   mCurButtons.resize(mNumButtons + mAxisButtonIndices.size());

   // Setup axis as button stuff
   mAxisToButtonIndexLookup.clear();
   mAxisToButtonIndexLookup.resize(mNumAxes, -1);            // Default to -1, meaning no axis button
   for(unsigned i=0;i<mAxisButtonIndices.size(); ++i)       // For each configured axis index
   {
      unsigned virtual_btn_index = (mNumButtons+i);                     // Index of the virtual button from the axis
      vprASSERT(virtual_btn_index < mCurButtons.size() && "Virtual button index out of range");
      unsigned axis_index = mAxisButtonIndices[i];                      // Index of the axis we are mapping
      mAxisToButtonIndexLookup[axis_index] = int(virtual_btn_index);    // Setup the mapping
   }

   return true;
}

/** Stops sampling.
* Drop connection to joystick and clear everything.
*/
bool LinuxJoydev::stopSampling()
{
   if(mJsFD > 0)
   {
      close(mJsFD);     // Close the joystick device
   }

   return true;
}

/**
 * Updates to the sampled data.
 *
 * @pre None.
 * @post Most recent value is copied over to temp area.
 */
void LinuxJoydev::updateData()
{
   // -- Read in any new pending events
   js_event cur_event;

   // While events pending
   while (read(mJsFD, &cur_event, sizeof(struct js_event)) > 0)
   {
      if(cur_event.type & JS_EVENT_BUTTON)
      {
         //std::cout << "ljs: btn: " << unsigned(cur_event.number) << " val:" << cur_event.value << std::endl;
         unsigned btn_number = unsigned(cur_event.number);
         vprASSERT(btn_number < mCurButtons.size() && "Button out of range");
         mCurButtons[btn_number] = cur_event.value;         // Assign the new button value (0,1)
         mCurButtons[btn_number].setTime();                 // Set timestamp to now
      }
      else if(cur_event.type & JS_EVENT_AXIS)
      {
         //std::cout << "ljs: axis: " << unsigned(cur_event.number) << " val:" << cur_event.value << std::endl;
         unsigned axis_number = unsigned(cur_event.number);
         vprASSERT(axis_number < mCurAxes.size() && "Axis out of range");
         vprASSERT(axis_number < mCurAxesRanges.size() && "Axis out of range");

         // Verify range (expand if needed)
         axis_range_t axis_range = mCurAxesRanges[axis_number];
         if(cur_event.value < axis_range.first)
         {
            axis_range.first = cur_event.value;
            mCurAxesRanges[axis_number] = axis_range;
         }
         if(cur_event.value > axis_range.second)
         {
            axis_range.second = cur_event.value;
            mCurAxesRanges[axis_number] = axis_range;
         }

         // norm = (val - min)/(min+max)
         float norm_value = (float(cur_event.value) - axis_range.first)/(axis_range.first+axis_range.second);
         /*
         std::cout << "axis: " << axis_number
                   << "  value: " << cur_event.value
                   << "  norm:" << norm_value
                   << "  range: [" << axis_range.first << " - " << axis_range.second << "]" << std::endl;
                   */

         mCurAxes[axis_number] = norm_value;
         mCurAxes[axis_number].setTime();

         // Check for axis buttons
         // - If we have a mapping
         // - If axis is gt 0.5, then btn is down
         if(mAxisToButtonIndexLookup[axis_number] != -1)    // If we map to a virtual button
         {
            unsigned vir_btn_index = mAxisToButtonIndexLookup[axis_number];
            vprASSERT(vir_btn_index < mCurButtons.size() && "Virtual button index out of range");
            mCurButtons[vir_btn_index] = ( (norm_value > 0.5f) ? 1 : 0);
            mCurButtons[vir_btn_index].setTime();
         }
      }
   }

   // Check to make sure error was just no-pending events
   if(errno != EAGAIN)
   {
      vprDEBUG(vprDBG_ALL, vprDBG_CRITICAL_LVL) << "ERROR: Error reading linux joystick.\n" << vprDEBUG_FLUSH;
      return;
   }

   addDigitalSample(mCurButtons);
   swapDigitalBuffers();

   addAnalogSample(mCurAxes);
   swapAnalogBuffers();
}

} // End of gadget namespace
<commit_msg>bug fix: be smarter about finding the range of the joystick device bug fix: calculate the normalalized value correctly<commit_after>/*************** <auto-copyright.pl BEGIN do not edit this line> **************
 *
 * VR Juggler is (C) Copyright 1998-2003 by Iowa State University
 *
 * Original Authors:
 *   Allen Bierbaum, Christopher Just,
 *   Patrick Hartling, Kevin Meinert,
 *   Carolina Cruz-Neira, Albert Baker
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 * -----------------------------------------------------------------
 * File:          $RCSfile$
 * Date modified: $Date$
 * Version:       $Revision$
 * -----------------------------------------------------------------
 *
 *************** <auto-copyright.pl END do not edit this line> ***************/

#include <gadget/Devices/DriverConfig.h>
#include <vpr/Util/Debug.h>
#include <jccl/Config/ConfigElement.h>
#include <gadget/Type/DeviceConstructor.h>
#include <gadget/Util/Debug.h>

#include <drivers/Open/LinuxJoydev/LinuxJoydev.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <fcntl.h>

#include <linux/joystick.h>      // Get the joystick abilities

extern "C"
{

GADGET_DRIVER_EXPORT(void) initDevice(gadget::InputManager* inputMgr)
{
   new gadget::DeviceConstructor<gadget::LinuxJoydev>(inputMgr);
}

}

namespace gadget
{

/** Constructor. */
LinuxJoydev::LinuxJoydev()
{;}

/**
 * Destructor.
 *
 * @pre None.
 * @post Shared memory is released.
 */
LinuxJoydev::~LinuxJoydev()
{
}

std::string LinuxJoydev::getElementType()
{
   return "linux_joydev";
}

/**
 *
 */
bool LinuxJoydev::config(jccl::ConfigElementPtr e)
{
   if(! (Input::config(e) && Digital::config(e) && Analog::config(e)))
   {
      return false;
   }

   mJsLabel = e->getName();
   mPortName = e->getProperty<std::string>("port_name");

   unsigned num_axis_buttons = e->getNum("axis_buttons");
   for(unsigned i=0;i<num_axis_buttons;++i)
   {
      unsigned idx = e->getProperty<int>("axis_buttons", i);
      mAxisButtonIndices.push_back(idx);
   }

   return true;
}

/** Begin sampling.
* Connect to the joystick and prepare to read.
*/
bool LinuxJoydev::startSampling()
{
   vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CONFIG_STATUS_LVL) << "Opening Linux Joystick driver on port: " << mPortName << std::endl << vprDEBUG_FLUSH;

   mJsFD = open(mPortName.c_str(), O_RDONLY | O_NONBLOCK);   // Open the joystick non-blocking

   if(mJsFD < 0)
   {
      vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CRITICAL_LVL) << "ERROR: Failed to open Linux Joystick: " << mPortName << std::endl << vprDEBUG_FLUSH;
      return false;
   }

   // Read in the settings
   int version;
   unsigned char num_axes, num_buttons;
   char js_name[255];

   ioctl(mJsFD, JSIOCGVERSION, &version);
   ioctl(mJsFD, JSIOCGAXES, &num_axes);
   ioctl(mJsFD, JSIOCGBUTTONS, &num_buttons);

   mNumAxes = num_axes;
   mNumButtons = num_buttons;

   // Get joystick name
   if (ioctl(mJsFD, JSIOCGNAME(sizeof(js_name)), js_name) < 0)
   {  mPhysicalJsName = std::string("Unknown"); }
   else
   {  mPhysicalJsName = js_name; }

   // Output joystick description
   vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CONFIG_STATUS_LVL)
         << "  joystick label: " << mJsLabel << std::endl
         << "   joystick name: " << mPhysicalJsName << std::endl
         << "            axes: " << mNumAxes << std::endl
         << "         buttons: " << mNumButtons << std::endl
         << "      driver ver: " << version << std::endl
         << "    axis buttons: ";

   for(unsigned i=0;i<mAxisButtonIndices.size(); ++i)
   { vprDEBUG_CONTnl(gadgetDBG_INPUT_MGR, vprDBG_CONFIG_STATUS_LVL) << mAxisButtonIndices[i] << " "; }
   vprDEBUG_CONTnl(gadgetDBG_INPUT_MGR, vprDBG_CONFIG_STATUS_LVL) << std::endl << vprDEBUG_FLUSH;

   // Allocate initial device data
   // - By default this will clear them out
   mCurAxes.resize(mNumAxes);
   mCurAxesRanges.resize(mNumAxes, axis_range_t(0,1));             // Initialize ranges to 0,255
   mCurButtons.resize(mNumButtons + mAxisButtonIndices.size());

   // Setup axis as button stuff
   mAxisToButtonIndexLookup.clear();
   mAxisToButtonIndexLookup.resize(mNumAxes, -1);            // Default to -1, meaning no axis button
   for(unsigned i=0;i<mAxisButtonIndices.size(); ++i)       // For each configured axis index
   {
      unsigned virtual_btn_index = (mNumButtons+i);                     // Index of the virtual button from the axis
      vprASSERT(virtual_btn_index < mCurButtons.size() && "Virtual button index out of range");
      unsigned axis_index = mAxisButtonIndices[i];                      // Index of the axis we are mapping
      mAxisToButtonIndexLookup[axis_index] = int(virtual_btn_index);    // Setup the mapping
   }

   return true;
}

/** Stops sampling.
* Drop connection to joystick and clear everything.
*/
bool LinuxJoydev::stopSampling()
{
   if(mJsFD > 0)
   {
      close(mJsFD);     // Close the joystick device
   }

   return true;
}

/**
 * Updates to the sampled data.
 *
 * @pre None.
 * @post Most recent value is copied over to temp area.
 */
void LinuxJoydev::updateData()
{
   // -- Read in any new pending events
   js_event cur_event;

   // While events pending
   while (read(mJsFD, &cur_event, sizeof(struct js_event)) > 0)
   {
      if(cur_event.type & JS_EVENT_BUTTON)
      {
         //std::cout << "ljs: btn: " << unsigned(cur_event.number) << " val:" << cur_event.value << std::endl;
         unsigned btn_number = unsigned(cur_event.number);
         vprASSERT(btn_number < mCurButtons.size() && "Button out of range");
         mCurButtons[btn_number] = cur_event.value;         // Assign the new button value (0,1)
         mCurButtons[btn_number].setTime();                 // Set timestamp to now
      }
      else if(cur_event.type & JS_EVENT_AXIS)
      {
         //std::cout << "ljs: axis: " << unsigned(cur_event.number) << " val:" << cur_event.value << std::endl;
         unsigned axis_number = unsigned(cur_event.number);
         vprASSERT(axis_number < mCurAxes.size() && "Axis out of range");
         vprASSERT(axis_number < mCurAxesRanges.size() && "Axis out of range");

         float norm_value = 0;
         // Verify range (expand if needed)
         axis_range_t axis_range = mCurAxesRanges[axis_number];
         if(cur_event.value < axis_range.first)
         {
            axis_range.first = cur_event.value;
            mCurAxesRanges[axis_number] = axis_range;
         }

         else if(cur_event.value > axis_range.second)
         {
            axis_range.second = cur_event.value;
            mCurAxesRanges[axis_number] = axis_range;
         }

         else
         {
            norm_value = (float(cur_event.value) - axis_range.first)/(axis_range.second-axis_range.first);
         }

         mCurAxes[axis_number] = norm_value;
         mCurAxes[axis_number].setTime();

         // Check for axis buttons
         // - If we have a mapping
         // - If axis is gt 0.5, then btn is down
         if(mAxisToButtonIndexLookup[axis_number] != -1)    // If we map to a virtual button
         {
            unsigned vir_btn_index = mAxisToButtonIndexLookup[axis_number];
            vprASSERT(vir_btn_index < mCurButtons.size() && "Virtual button index out of range");
            mCurButtons[vir_btn_index] = ( (norm_value > 0.5f) ? 1 : 0);
            mCurButtons[vir_btn_index].setTime();
         }
      }
   }

   // Check to make sure error was just no-pending events
   if(errno != EAGAIN)
   {
      vprDEBUG(vprDBG_ALL, vprDBG_CRITICAL_LVL) << "ERROR: Error reading linux joystick.\n" << vprDEBUG_FLUSH;
      return;
   }

   addDigitalSample(mCurButtons);
   swapDigitalBuffers();

   addAnalogSample(mCurAxes);
   swapAnalogBuffers();
}

} // End of gadget namespace
<|endoftext|>


<commit_before>#pragma once

#include <vector>

namespace worldlib
{

//////////////////////////////////////////////////////////////////////////////
/// \file Decompress.hpp
/// \brief Contains various functions for decompressing data
///
/// \addtogroup Decompression
///  @{
//////////////////////////////////////////////////////////////////////////////

	////////////////////////////////////////////////////////////
	/// \brief Decompresses data compressed in the LZ2 format.
	/// \details In general you'll want the functions in level.hpp related to getting graphics files instead, but this may be useful if you have your own data compressed like this.
	///
	/// \param compressedDataStart	An iterator pointing to the beginning of the compressed data
	/// \param compressedDataEnd	An iterator pointing to the end of the compressed data or any valid point after that (for example, the end of the ROM).
	/// \param out			Where to output the data
	/// \param compressedSize	Will contain the size of the compressed data after the function ends if it is not nullptr
	/// \param decompressedSize	Will contain the size of the decompressed data after the function ends if it is not nullptr
	///
	/// \return Iterator pointing to the end of your decompressed data
	///
	/// \throws std::runtime_error An error occurred while decompressing the data.  Either there was an unrecognized bit sequence or there was not enough data to decompress
	///
	/// \see decompressGraphicsFile
	///
	////////////////////////////////////////////////////////////
	template <typename inputIteratorType, typename outputIteratorType>
	outputIteratorType decompressLZ2(inputIteratorType compressedDataStart, inputIteratorType compressedDataEnd, outputIteratorType out, int *compressedSize = nullptr, int *decompressedSize = nullptr);

	////////////////////////////////////////////////////////////
	/// \brief Decompresses data compressed in the LZ3 format.
	/// \details In general you'll want the functions in level.hpp related to getting graphics files instead, but this may be useful if you have your own data compressed like this.
	///
	/// \param compressedDataStart	An iterator pointing to the beginning of the compressed data
	/// \param compressedDataEnd	An iterator pointing to the end of the compressed data or any valid point after that (for example, the end of the ROM).
	/// \param out			Where to output the data
	/// \param compressedSize	Will contain the size of the compressed data after the function ends if it is not nullptr
	/// \param decompressedSize	Will contain the size of the decompressed data after the function ends if it is not nullptr
	///
	/// \return Iterator pointing to the end of your decompressed data
	///
	/// \throws std::runtime_error An error occurred while decompressing the data.  Either there was an unrecognized bit sequence or there was not enough data to decompress
	///
	/// \see decompressGraphicsFile
	///
	////////////////////////////////////////////////////////////
	template <typename inputIteratorType, typename outputIteratorType>
	outputIteratorType decompressLZ3(inputIteratorType compressedDataStart, inputIteratorType compressedDataEnd, outputIteratorType out, int *compressedSize = nullptr, int *decompressedSize = nullptr);

//////////////////////////////////////////////////////////////////////////////
///  @}
//////////////////////////////////////////////////////////////////////////////
}

#include "decompress.inl"<commit_msg>Properly added compression function declarations to the header file<commit_after>#pragma once

#include <vector>

#ifndef WORLDLIB_IGNORE_DLL_FUNCTIONS
#include <Windows.h>
#include "../DLLcode/LunarDLL.h"
#undef max
#undef min
#endif

namespace worldlib
{

//////////////////////////////////////////////////////////////////////////////
/// \file Decompress.hpp
/// \brief Contains various functions for decompressing data
///
/// \addtogroup Decompression
///  @{
//////////////////////////////////////////////////////////////////////////////

	////////////////////////////////////////////////////////////
	/// \brief Decompresses data compressed in the LZ2 format.
	/// \details In general you'll want the functions in level.hpp related to getting graphics files instead, but this may be useful if you have your own data compressed like this.
	///
	/// \param compressedDataStart	An iterator pointing to the beginning of the compressed data
	/// \param compressedDataEnd	An iterator pointing to the end of the compressed data or any valid point after that (for example, the end of the ROM).
	/// \param out			Where to output the data
	/// \param compressedSize	Will contain the size of the compressed data after the function ends if it is not nullptr
	/// \param decompressedSize	Will contain the size of the decompressed data after the function ends if it is not nullptr
	///
	/// \return Iterator pointing to the end of your decompressed data
	///
	/// \throws std::runtime_error An error occurred while decompressing the data.  Either there was an unrecognized bit sequence or there was not enough data to decompress
	///
	/// \see decompressGraphicsFile, decompressData
	///
	////////////////////////////////////////////////////////////
	template <typename inputIteratorType, typename outputIteratorType>
	outputIteratorType decompressLZ2(inputIteratorType compressedDataStart, inputIteratorType compressedDataEnd, outputIteratorType out, int *compressedSize = nullptr, int *decompressedSize = nullptr);

	////////////////////////////////////////////////////////////
	/// \brief Decompresses data compressed in the LZ3 format.
	/// \details In general you'll want the functions in level.hpp related to getting graphics files instead, but this may be useful if you have your own data compressed like this.
	///
	/// \param compressedDataStart	An iterator pointing to the beginning of the compressed data
	/// \param compressedDataEnd	An iterator pointing to the end of the compressed data or any valid point after that (for example, the end of the ROM).
	/// \param out			Where to output the data
	/// \param compressedSize	Will contain the size of the compressed data after the function ends if it is not nullptr
	/// \param decompressedSize	Will contain the size of the decompressed data after the function ends if it is not nullptr
	///
	/// \return Iterator pointing to the end of your decompressed data
	///
	/// \throws std::runtime_error An error occurred while decompressing the data.  Either there was an unrecognized bit sequence or there was not enough data to decompress
	///
	/// \see decompressGraphicsFile, decompressData
	///
	////////////////////////////////////////////////////////////
	template <typename inputIteratorType, typename outputIteratorType>
	outputIteratorType decompressLZ3(inputIteratorType compressedDataStart, inputIteratorType compressedDataEnd, outputIteratorType out, int *compressedSize = nullptr, int *decompressedSize = nullptr);

	////////////////////////////////////////////////////////////
	/// \brief Decompresses data compressed in the format the ROM uses
	///
	/// \param romStart		An iterator pointing to the start of your ROM data
	/// \param romEnd		An iterator pointing to the end of your ROM data
	/// \param compressedDataStart	An iterator pointing to the beginning of the compressed data
	/// \param compressedDataEnd	An iterator pointing to the end of the compressed data or any valid point after that (for example, the end of the ROM).
	/// \param out			Where to output the data
	/// \param compressedSize	Will contain the size of the compressed data after the function ends if it is not nullptr
	/// \param decompressedSize	Will contain the size of the decompressed data after the function ends if it is not nullptr
	///
	/// \return Iterator pointing to the end of your decompressed data
	///
	/// \throws std::runtime_error An error occurred while decompressing the data.  Either there was an unrecognized bit sequence or there was not enough data to decompress
	///
	/// \see decompressGraphicsFile
	///
	////////////////////////////////////////////////////////////
	template <typename romIteratorType, typename inputIteratorType, typename outputIteratorType>
	outputIteratorType decompressData(romIteratorType romStart, romIteratorType romEnd, inputIteratorType compressedDataStart, inputIteratorType compressedDataEnd, outputIteratorType out, int *compressedSize = nullptr, int *decompressedSize = nullptr);

	// Compression functions all rely on the Lunar Compress DLL
	#ifndef WORLDLIB_IGNORE_DLL_FUNCTIONS

	namespace internal
	{
		////////////////////////////////////////////////////////////
		/// \brief Compresses data compressed in any format compatible with Lunar Compress
		///
		/// \param rawDataStart		An iterator pointing to the beginning of the raw data to compress
		/// \param rawDataEnd		An iterator pointing to the end of the raw data to compress
		/// \param out			Where to output the compressed data
		/// \compressionType		The compression type. See LunarDLL.h
		/// \param compressedSize	Will contain the size of the compressed data after the function ends if it is not nullptr
		///
		/// \return Iterator pointing to the end of your compressed data
		///
		/// \throws std::runtime_error Lunar Compress.dll could not be loaded or there was an error compressing the data.  The first is more likely.
		///
		////////////////////////////////////////////////////////////
		template <typename inputIteratorType, typename outputIteratorType>
		outputIteratorType compressGeneral(inputIteratorType rawDataStart, inputIteratorType rawDataEnd, outputIteratorType out, int compressionType, int *compressedSize);
	}

	////////////////////////////////////////////////////////////
	/// \brief Compresses data compressed in the LZ2 format.
	/// \details Please note that this function requires Lunar Compress.dll.  See also compressData, which takes into account the ROM's current compression type.
	///
	/// \param rawDataStart		An iterator pointing to the beginning of the raw data to compress
	/// \param rawDataEnd		An iterator pointing to the end of the raw data to compress
	/// \param out			Where to output the compressed data
	/// \param compressedSize	Will contain the size of the compressed data after the function ends if it is not nullptr
	///
	/// \return Iterator pointing to the end of your compressed data
	///
	/// \throws std::runtime_error Lunar Compress.dll could not be loaded or there was an error compressing the data.  The first is more likely.
	///
	/// \see compressData
	///
	////////////////////////////////////////////////////////////
	template <typename inputIteratorType, typename outputIteratorType>
	outputIteratorType compressLZ2(inputIteratorType rawDataStart, inputIteratorType rawDataEnd, outputIteratorType out, int *compressedSize);

	////////////////////////////////////////////////////////////
	/// \brief Compresses data compressed in the LZ3 format.
	/// \details Please note that this function requires Lunar Compress.dll.  See also compressData, which takes into account the ROM's current compression type.
	///
	/// \param rawDataStart		An iterator pointing to the beginning of the raw data to compress
	/// \param rawDataEnd		An iterator pointing to the end of the raw data to compress
	/// \param out			Where to output the compressed data
	/// \param compressedSize	Will contain the size of the compressed data after the function ends if it is not nullptr
	///
	/// \return Iterator pointing to the end of your compressed data
	///
	/// \throws std::runtime_error Lunar Compress.dll could not be loaded or there was an error compressing the data.  The first is more likely.
	///
	/// \see compressData
	///
	////////////////////////////////////////////////////////////
	template <typename inputIteratorType, typename outputIteratorType>
	outputIteratorType compressLZ3(inputIteratorType rawDataStart, inputIteratorType rawDataEnd, outputIteratorType out, int *compressedSize);

	////////////////////////////////////////////////////////////
	/// \brief Compresses data compressed in the compression format your ROM uses format.
	/// \details Please note that this function requires Lunar Compress.dll.  See also compressData, which takes into account the ROM's current compression type.
	///
	/// \param rawDataStart		An iterator pointing to the beginning of the raw data to compress
	/// \param rawDataEnd		An iterator pointing to the end of the raw data to compress
	/// \param out			Where to output the compressed data
	/// \param compressedSize	Will contain the size of the compressed data after the function ends if it is not nullptr
	///
	/// \return Iterator pointing to the end of your compressed data
	///
	/// \throws std::runtime_error Lunar Compress.dll could not be loaded or there was an error compressing the data.  The first is more likely.
	///
	////////////////////////////////////////////////////////////
	template <typename romIteratorType, typename inputIteratorType, typename outputIteratorType>
	outputIteratorType compressData(romIteratorType romStart, romIteratorType romEnd, inputIteratorType rawDataStart, inputIteratorType rawDataEnd, outputIteratorType out, int *compressedSize);

	#endif

//////////////////////////////////////////////////////////////////////////////
///  @}
//////////////////////////////////////////////////////////////////////////////
}

#include "Compression.inl"<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used 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.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/

#include "dragtool.h"

#include "formeditorscene.h"
#include "formeditorview.h"
#include "formeditorwidget.h"
#include "itemutilfunctions.h"
#include <customdraganddrop.h>
#include <metainfo.h>
#include <rewritingexception.h>

#include "resizehandleitem.h"

#include <QApplication>
#include <QGraphicsSceneMouseEvent>
#include <QtDebug>
#include <QMessageBox>
#include <QTimer>

namespace QmlDesigner {

namespace Internal {
void TimerHandler::clearMoveDelay()
{
    m_dragTool->clearMoveDelay();
}

}

DragTool::DragTool(FormEditorView *editorView)
    : AbstractFormEditorTool(editorView),
    m_moveManipulator(editorView->scene()->manipulatorLayerItem(), editorView),
    m_selectionIndicator(editorView->scene()->manipulatorLayerItem()),
    m_timerHandler(new Internal::TimerHandler(this)),
    m_blockMove(false),
    m_Aborted(false)
{
}

DragTool::~DragTool()
{

}

void DragTool::clear()
{
    m_moveManipulator.clear();
    m_selectionIndicator.clear();
    m_movingItem.clear();
}

void DragTool::mousePressEvent(const QList<QGraphicsItem*> &,
                                            QGraphicsSceneMouseEvent *)
{

}

void DragTool::mouseMoveEvent(const QList<QGraphicsItem*> &,
                                           QGraphicsSceneMouseEvent *)
{

}

void DragTool::hoverMoveEvent(const QList<QGraphicsItem*> &,
                        QGraphicsSceneMouseEvent * /*event*/)
{

}

void DragTool::keyPressEvent(QKeyEvent *event)
{
    if (event->key() == Qt::Key_Escape) {
        abort();
        event->accept();
        view()->changeToSelectionTool();
    }
}

void DragTool::keyReleaseEvent(QKeyEvent *)
{

}

void DragTool::mouseReleaseEvent(const QList<QGraphicsItem*> &/*itemList*/,
                                 QGraphicsSceneMouseEvent *)
{

}

void DragTool::mouseDoubleClickEvent(const QList<QGraphicsItem*> & /*itemList*/,
                                              QGraphicsSceneMouseEvent * /*event*/)
{

}

void DragTool::itemsAboutToRemoved(const QList<FormEditorItem*> & /* removedItemList */)
{

}

void DragTool::selectedItemsChanged(const QList<FormEditorItem*> &)
{

}

void DragTool::updateMoveManipulator()
{
    if (m_moveManipulator.isActive())
        return;
}

void DragTool::beginWithPoint(const QPointF &beginPoint)
{
    m_movingItem = scene()->itemForQmlItemNode(m_dragNode);

    m_moveManipulator.setItem(m_movingItem.data());
    m_moveManipulator.begin(beginPoint);
}

void DragTool::createQmlItemNode(const ItemLibraryEntry &itemLibraryEntry, QmlItemNode parentNode, QPointF scenePos)
{
    MetaInfo metaInfo = MetaInfo::global();

    FormEditorItem *parentItem = scene()->itemForQmlItemNode(parentNode);
    QPointF pos = parentItem->mapFromScene(scenePos);

    m_dragNode = view()->createQmlItemNode(itemLibraryEntry, pos, parentNode);

    Q_ASSERT(m_dragNode.modelNode().isValid());

    QList<QmlItemNode> nodeList;
    nodeList.append(m_dragNode);
    m_selectionIndicator.setItems(scene()->itemsForQmlItemNodes(nodeList));
}

void DragTool::createQmlItemNodeFromImage(const QString &imageName, QmlItemNode parentNode, QPointF scenePos)
{
    if (!parentNode.isValid())
        return;

    MetaInfo metaInfo = MetaInfo::global();

    FormEditorItem *parentItem = scene()->itemForQmlItemNode(parentNode);
    QPointF pos = parentItem->mapFromScene(scenePos);

    m_dragNode = view()->createQmlItemNodeFromImage(imageName, pos, parentNode);

    QList<QmlItemNode> nodeList;
    nodeList.append(m_dragNode);
    m_selectionIndicator.setItems(scene()->itemsForQmlItemNodes(nodeList));
}

FormEditorItem* DragTool::calculateContainer(const QPointF &point, FormEditorItem * currentItem)
{
    QList<QGraphicsItem *> list = scene()->items(point);
    foreach (QGraphicsItem *item, list) {
         FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item);
         if (formEditorItem && formEditorItem != currentItem && formEditorItem->isContainer())
             return formEditorItem;
    }

    if (scene()->rootFormEditorItem())
        return scene()->rootFormEditorItem();
    return 0;
}

void DragTool::formEditorItemsChanged(const QList<FormEditorItem*> & itemList)
{
    if (m_movingItem && itemList.contains(m_movingItem.data())) {
        QList<FormEditorItem*> updateItemList;
        updateItemList.append(m_movingItem.data());
        m_selectionIndicator.updateItems(updateItemList);
    }
}

void DragTool::instancesCompleted(const QList<FormEditorItem*> &itemList)
{
    foreach (FormEditorItem* item, itemList)
        if (item->qmlItemNode() == m_dragNode)
            clearMoveDelay();
    QmlDesignerItemLibraryDragAndDrop::CustomDragAndDrop::hide();
}

void DragTool::instancesParentChanged(const QList<FormEditorItem *> &itemList)
{
    m_moveManipulator.synchronizeInstanceParent(itemList);
}

void DragTool::clearMoveDelay()
{
    if (!m_blockMove)
        return;
    m_blockMove = false;
    if  (m_dragNode.isValid())
        beginWithPoint(m_startPoint);
}

void DragTool::abort()
{
    if (m_Aborted)
        return;

    m_Aborted = true;

    if (m_dragNode.isValid())
        m_dragNode.destroy();

    QmlDesignerItemLibraryDragAndDrop::CustomDragAndDrop::hide();

    if (m_rewriterTransaction.isValid())
        m_rewriterTransaction.commit();

}

void DragTool::dropEvent(QGraphicsSceneDragDropEvent * event)
{
    if (event->mimeData()->hasFormat("application/vnd.bauhaus.itemlibraryinfo") ||
       event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) {
        event->accept();
        end(event->scenePos());
        //Q_ASSERT(m_token.isValid());
        try {
            m_rewriterTransaction.commit();
        } catch (RewritingException &e) {
            QMessageBox::warning(0, "Error", e.description());
        }
        if (m_dragNode.isValid()) {
            QList<QmlItemNode> nodeList;
            nodeList.append(m_dragNode);
            view()->setSelectedQmlItemNodes(nodeList);
        }
        m_dragNode = ModelNode();
        view()->changeToSelectionTool();
    }
}

static ItemLibraryEntry itemLibraryEntryFromData(const QByteArray &data)
{
    QDataStream stream(data);

    ItemLibraryEntry itemLibraryEntry;
    stream >> itemLibraryEntry;

    return itemLibraryEntry;
}

void DragTool::dragEnterEvent(QGraphicsSceneDragDropEvent * event)
{
    if (event->mimeData()->hasFormat("application/vnd.bauhaus.itemlibraryinfo") ||
        event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) {
        QList<Import> importToBeAddedList;
        m_blockMove = false;
        if (event->mimeData()->hasFormat("application/vnd.bauhaus.itemlibraryinfo")) {
            view()->widget()->setFocus();
            m_Aborted = false;
            Q_ASSERT(!event->mimeData()->data("application/vnd.bauhaus.itemlibraryinfo").isEmpty());
            ItemLibraryEntry itemLibraryEntry = itemLibraryEntryFromData(event->mimeData()->data("application/vnd.bauhaus.itemlibraryinfo"));
            if (!itemLibraryEntry.requiredImport().isEmpty()) {
                const QString newImportUrl = itemLibraryEntry.requiredImport();
                const QString newImportVersion = QString("%1.%2").arg(QString::number(itemLibraryEntry.majorVersion()), QString::number(itemLibraryEntry.minorVersion()));
                Import newImport = Import::createLibraryImport(newImportUrl, newImportVersion);

                if (!view()->model()->hasImport(newImport, true, true)) {
                    importToBeAddedList.append(newImport);
                }

            }
        }

        view()->model()->changeImports(importToBeAddedList, QList<Import>());

        if (!m_rewriterTransaction.isValid()) {
            view()->clearSelectedModelNodes();
            m_rewriterTransaction = view()->beginRewriterTransaction();
        }
    }
}

void DragTool::dragLeaveEvent(QGraphicsSceneDragDropEvent * event)
{
    if (event->mimeData()->hasFormat("application/vnd.bauhaus.itemlibraryinfo") ||
       event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) {
        event->accept();
        if (m_dragNode.isValid())
            m_dragNode.destroy();
        end(event->scenePos());

        try {
            m_rewriterTransaction.commit();
        } catch (RewritingException &e) {
            QMessageBox::warning(0, "Error", e.description());
        }

        QmlDesignerItemLibraryDragAndDrop::CustomDragAndDrop::show();
        QList<QmlItemNode> nodeList;
        view()->setSelectedQmlItemNodes(nodeList);
        view()->changeToSelectionTool();
    }
}

void DragTool::dragMoveEvent(QGraphicsSceneDragDropEvent * event)
{
    if (m_blockMove)
        return;

    if (m_Aborted) {
        event->ignore();
        return;
    }
    if (QmlDesignerItemLibraryDragAndDrop::CustomDragAndDrop::isAnimated())
        return;
    if (event->mimeData()->hasFormat("application/vnd.bauhaus.itemlibraryinfo") ||
       event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) {
        event->accept();
        QPointF scenePos = event->scenePos();
        if  (m_dragNode.isValid()) {

            FormEditorItem *parentItem = calculateContainer(event->scenePos() + QPoint(2, 2));
            if (!parentItem) {      //if there is no parent any more - the use left the scene
                end(event->scenePos());
                QmlDesignerItemLibraryDragAndDrop::CustomDragAndDrop::show();
                m_dragNode.destroy(); //delete the node then
                return;
            }
            //move
            move(event->scenePos());
        } else {
            //create new node  if container
            if (m_dragNode.modelNode().isValid())
                return;

            FormEditorItem *parentItem = calculateContainer(scenePos);
            if (!parentItem)
                return;
            QmlItemNode parentNode;
            if (parentItem)
                parentNode = parentItem->qmlItemNode();

            if (event->mimeData()->hasFormat("application/vnd.bauhaus.itemlibraryinfo")) {
                Q_ASSERT(!event->mimeData()->data("application/vnd.bauhaus.itemlibraryinfo").isEmpty());
                ItemLibraryEntry itemLibraryEntry = itemLibraryEntryFromData(event->mimeData()->data("application/vnd.bauhaus.itemlibraryinfo"));
                createQmlItemNode(itemLibraryEntry, parentNode, event->scenePos());
            } else if (event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) {
                Q_ASSERT(!event->mimeData()->data("application/vnd.bauhaus.libraryresource").isEmpty());
                QString imageName = QString::fromUtf8((event->mimeData()->data("application/vnd.bauhaus.libraryresource")));
                createQmlItemNodeFromImage(imageName, parentNode, event->scenePos());
            } else Q_ASSERT(false);
            m_blockMove = true;
            m_startPoint = event->scenePos();
            QTimer::singleShot(1000, m_timerHandler.data(), SLOT(clearMoveDelay()));
        }
    }

    if (event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) {
    }
}

void  DragTool::end(QPointF scenePos)
{
    m_moveManipulator.end(scenePos);
    clear();
}

void  DragTool::move(QPointF scenePos)
{
    if (!m_movingItem)
        return;

    FormEditorItem *containerItem = calculateContainer(scenePos - QPoint(2, 2), m_movingItem.data());
    if (containerItem && m_movingItem->parentItem() &&
       containerItem != m_movingItem->parentItem()) {

        m_moveManipulator.reparentTo(containerItem);
    }

    //MoveManipulator::Snapping useSnapping = MoveManipulator::NoSnapping;
    MoveManipulator::Snapping useSnapping = MoveManipulator::UseSnapping;
   /* if (event->modifiers().testFlag(Qt::ControlModifier) != view()->isSnapButtonChecked())
        useSnapping = MoveManipulator::UseSnapping;*/

    m_moveManipulator.update(scenePos, useSnapping, MoveManipulator::UseBaseState);
}

}
<commit_msg>QmlDesigner.dragAndDrop: crash fix<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used 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.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/

#include "dragtool.h"

#include "formeditorscene.h"
#include "formeditorview.h"
#include "formeditorwidget.h"
#include "itemutilfunctions.h"
#include <customdraganddrop.h>
#include <metainfo.h>
#include <rewritingexception.h>

#include "resizehandleitem.h"

#include <QApplication>
#include <QGraphicsSceneMouseEvent>
#include <QtDebug>
#include <QMessageBox>
#include <QTimer>

namespace QmlDesigner {

namespace Internal {
void TimerHandler::clearMoveDelay()
{
    m_dragTool->clearMoveDelay();
}

}

DragTool::DragTool(FormEditorView *editorView)
    : AbstractFormEditorTool(editorView),
    m_moveManipulator(editorView->scene()->manipulatorLayerItem(), editorView),
    m_selectionIndicator(editorView->scene()->manipulatorLayerItem()),
    m_timerHandler(new Internal::TimerHandler(this)),
    m_blockMove(false),
    m_Aborted(false)
{
}

DragTool::~DragTool()
{

}

void DragTool::clear()
{
    m_moveManipulator.clear();
    m_selectionIndicator.clear();
    m_movingItem.clear();
}

void DragTool::mousePressEvent(const QList<QGraphicsItem*> &,
                                            QGraphicsSceneMouseEvent *)
{

}

void DragTool::mouseMoveEvent(const QList<QGraphicsItem*> &,
                                           QGraphicsSceneMouseEvent *)
{

}

void DragTool::hoverMoveEvent(const QList<QGraphicsItem*> &,
                        QGraphicsSceneMouseEvent * /*event*/)
{

}

void DragTool::keyPressEvent(QKeyEvent *event)
{
    if (event->key() == Qt::Key_Escape) {
        abort();
        event->accept();
        view()->changeToSelectionTool();
    }
}

void DragTool::keyReleaseEvent(QKeyEvent *)
{

}

void DragTool::mouseReleaseEvent(const QList<QGraphicsItem*> &/*itemList*/,
                                 QGraphicsSceneMouseEvent *)
{

}

void DragTool::mouseDoubleClickEvent(const QList<QGraphicsItem*> & /*itemList*/,
                                              QGraphicsSceneMouseEvent * /*event*/)
{

}

void DragTool::itemsAboutToRemoved(const QList<FormEditorItem*> & /* removedItemList */)
{

}

void DragTool::selectedItemsChanged(const QList<FormEditorItem*> &)
{

}

void DragTool::updateMoveManipulator()
{
    if (m_moveManipulator.isActive())
        return;
}

void DragTool::beginWithPoint(const QPointF &beginPoint)
{
    m_movingItem = scene()->itemForQmlItemNode(m_dragNode);

    m_moveManipulator.setItem(m_movingItem.data());
    m_moveManipulator.begin(beginPoint);
}

void DragTool::createQmlItemNode(const ItemLibraryEntry &itemLibraryEntry, QmlItemNode parentNode, QPointF scenePos)
{
    MetaInfo metaInfo = MetaInfo::global();

    FormEditorItem *parentItem = scene()->itemForQmlItemNode(parentNode);
    QPointF pos = parentItem->mapFromScene(scenePos);

    m_dragNode = view()->createQmlItemNode(itemLibraryEntry, pos, parentNode);

    Q_ASSERT(m_dragNode.modelNode().isValid());

    QList<QmlItemNode> nodeList;
    nodeList.append(m_dragNode);
    m_selectionIndicator.setItems(scene()->itemsForQmlItemNodes(nodeList));
}

void DragTool::createQmlItemNodeFromImage(const QString &imageName, QmlItemNode parentNode, QPointF scenePos)
{
    if (!parentNode.isValid())
        return;

    MetaInfo metaInfo = MetaInfo::global();

    FormEditorItem *parentItem = scene()->itemForQmlItemNode(parentNode);
    QPointF pos = parentItem->mapFromScene(scenePos);

    m_dragNode = view()->createQmlItemNodeFromImage(imageName, pos, parentNode);

    QList<QmlItemNode> nodeList;
    nodeList.append(m_dragNode);
    m_selectionIndicator.setItems(scene()->itemsForQmlItemNodes(nodeList));
}

static inline bool isAncestorOf(FormEditorItem *formEditorItem, FormEditorItem *newParentItem)
{
    if (formEditorItem && newParentItem)
        return formEditorItem->isAncestorOf(newParentItem);
    return false;
}

FormEditorItem* DragTool::calculateContainer(const QPointF &point, FormEditorItem * currentItem)
{
    QList<QGraphicsItem *> list = scene()->items(point);
    foreach (QGraphicsItem *item, list) {
         FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item);
         if (formEditorItem && formEditorItem != currentItem && formEditorItem->isContainer()
             && !isAncestorOf(currentItem, formEditorItem))
             return formEditorItem;
    }

    if (scene()->rootFormEditorItem())
        return scene()->rootFormEditorItem();
    return 0;
}

void DragTool::formEditorItemsChanged(const QList<FormEditorItem*> & itemList)
{
    if (m_movingItem && itemList.contains(m_movingItem.data())) {
        QList<FormEditorItem*> updateItemList;
        updateItemList.append(m_movingItem.data());
        m_selectionIndicator.updateItems(updateItemList);
    }
}

void DragTool::instancesCompleted(const QList<FormEditorItem*> &itemList)
{
    foreach (FormEditorItem* item, itemList)
        if (item->qmlItemNode() == m_dragNode)
            clearMoveDelay();
    QmlDesignerItemLibraryDragAndDrop::CustomDragAndDrop::hide();
}

void DragTool::instancesParentChanged(const QList<FormEditorItem *> &itemList)
{
    m_moveManipulator.synchronizeInstanceParent(itemList);
}

void DragTool::clearMoveDelay()
{
    if (!m_blockMove)
        return;
    m_blockMove = false;
    if  (m_dragNode.isValid())
        beginWithPoint(m_startPoint);
}

void DragTool::abort()
{
    if (m_Aborted)
        return;

    m_Aborted = true;

    if (m_dragNode.isValid())
        m_dragNode.destroy();

    QmlDesignerItemLibraryDragAndDrop::CustomDragAndDrop::hide();

    if (m_rewriterTransaction.isValid())
        m_rewriterTransaction.commit();

}

void DragTool::dropEvent(QGraphicsSceneDragDropEvent * event)
{
    if (event->mimeData()->hasFormat("application/vnd.bauhaus.itemlibraryinfo") ||
       event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) {
        event->accept();
        end(event->scenePos());
        //Q_ASSERT(m_token.isValid());
        try {
            m_rewriterTransaction.commit();
        } catch (RewritingException &e) {
            QMessageBox::warning(0, "Error", e.description());
        }
        if (m_dragNode.isValid()) {
            QList<QmlItemNode> nodeList;
            nodeList.append(m_dragNode);
            view()->setSelectedQmlItemNodes(nodeList);
        }
        m_dragNode = ModelNode();
        view()->changeToSelectionTool();
    }
}

static ItemLibraryEntry itemLibraryEntryFromData(const QByteArray &data)
{
    QDataStream stream(data);

    ItemLibraryEntry itemLibraryEntry;
    stream >> itemLibraryEntry;

    return itemLibraryEntry;
}

void DragTool::dragEnterEvent(QGraphicsSceneDragDropEvent * event)
{
    if (event->mimeData()->hasFormat("application/vnd.bauhaus.itemlibraryinfo") ||
        event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) {
        QList<Import> importToBeAddedList;
        m_blockMove = false;
        if (event->mimeData()->hasFormat("application/vnd.bauhaus.itemlibraryinfo")) {
            view()->widget()->setFocus();
            m_Aborted = false;
            Q_ASSERT(!event->mimeData()->data("application/vnd.bauhaus.itemlibraryinfo").isEmpty());
            ItemLibraryEntry itemLibraryEntry = itemLibraryEntryFromData(event->mimeData()->data("application/vnd.bauhaus.itemlibraryinfo"));
            if (!itemLibraryEntry.requiredImport().isEmpty()) {
                const QString newImportUrl = itemLibraryEntry.requiredImport();
                const QString newImportVersion = QString("%1.%2").arg(QString::number(itemLibraryEntry.majorVersion()), QString::number(itemLibraryEntry.minorVersion()));
                Import newImport = Import::createLibraryImport(newImportUrl, newImportVersion);

                if (!view()->model()->hasImport(newImport, true, true)) {
                    importToBeAddedList.append(newImport);
                }

            }
        }

        view()->model()->changeImports(importToBeAddedList, QList<Import>());

        if (!m_rewriterTransaction.isValid()) {
            view()->clearSelectedModelNodes();
            m_rewriterTransaction = view()->beginRewriterTransaction();
        }
    }
}

void DragTool::dragLeaveEvent(QGraphicsSceneDragDropEvent * event)
{
    if (event->mimeData()->hasFormat("application/vnd.bauhaus.itemlibraryinfo") ||
       event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) {
        event->accept();
        if (m_dragNode.isValid())
            m_dragNode.destroy();
        end(event->scenePos());

        try {
            m_rewriterTransaction.commit();
        } catch (RewritingException &e) {
            QMessageBox::warning(0, "Error", e.description());
        }

        QmlDesignerItemLibraryDragAndDrop::CustomDragAndDrop::show();
        QList<QmlItemNode> nodeList;
        view()->setSelectedQmlItemNodes(nodeList);
        view()->changeToSelectionTool();
    }
}

void DragTool::dragMoveEvent(QGraphicsSceneDragDropEvent * event)
{
    if (m_blockMove)
        return;

    if (m_Aborted) {
        event->ignore();
        return;
    }
    if (QmlDesignerItemLibraryDragAndDrop::CustomDragAndDrop::isAnimated())
        return;
    if (event->mimeData()->hasFormat("application/vnd.bauhaus.itemlibraryinfo") ||
       event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) {
        event->accept();
        QPointF scenePos = event->scenePos();
        if  (m_dragNode.isValid()) {

            FormEditorItem *parentItem = calculateContainer(event->scenePos() + QPoint(2, 2));
            if (!parentItem) {      //if there is no parent any more - the use left the scene
                end(event->scenePos());
                QmlDesignerItemLibraryDragAndDrop::CustomDragAndDrop::show();
                m_dragNode.destroy(); //delete the node then
                return;
            }
            //move
            move(event->scenePos());
        } else {
            //create new node  if container
            if (m_dragNode.modelNode().isValid())
                return;

            FormEditorItem *parentItem = calculateContainer(scenePos);
            if (!parentItem)
                return;
            QmlItemNode parentNode;
            if (parentItem)
                parentNode = parentItem->qmlItemNode();

            if (event->mimeData()->hasFormat("application/vnd.bauhaus.itemlibraryinfo")) {
                Q_ASSERT(!event->mimeData()->data("application/vnd.bauhaus.itemlibraryinfo").isEmpty());
                ItemLibraryEntry itemLibraryEntry = itemLibraryEntryFromData(event->mimeData()->data("application/vnd.bauhaus.itemlibraryinfo"));
                createQmlItemNode(itemLibraryEntry, parentNode, event->scenePos());
            } else if (event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) {
                Q_ASSERT(!event->mimeData()->data("application/vnd.bauhaus.libraryresource").isEmpty());
                QString imageName = QString::fromUtf8((event->mimeData()->data("application/vnd.bauhaus.libraryresource")));
                createQmlItemNodeFromImage(imageName, parentNode, event->scenePos());
            } else Q_ASSERT(false);
            m_blockMove = true;
            m_startPoint = event->scenePos();
            QTimer::singleShot(1000, m_timerHandler.data(), SLOT(clearMoveDelay()));
        }
    }

    if (event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) {
    }
}

void  DragTool::end(QPointF scenePos)
{
    m_moveManipulator.end(scenePos);
    clear();
}

void  DragTool::move(QPointF scenePos)
{
    if (!m_movingItem)
        return;

    FormEditorItem *containerItem = calculateContainer(scenePos - QPoint(2, 2), m_movingItem.data());
    if (containerItem && m_movingItem->parentItem() &&
       containerItem != m_movingItem->parentItem()) {

        m_moveManipulator.reparentTo(containerItem);
    }

    //MoveManipulator::Snapping useSnapping = MoveManipulator::NoSnapping;
    MoveManipulator::Snapping useSnapping = MoveManipulator::UseSnapping;
   /* if (event->modifiers().testFlag(Qt::ControlModifier) != view()->isSnapButtonChecked())
        useSnapping = MoveManipulator::UseSnapping;*/

    m_moveManipulator.update(scenePos, useSnapping, MoveManipulator::UseBaseState);
}

}
<|endoftext|>


<commit_before>#include "ConnectCall.h"

#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"

#include "MetaMethodRef.h"

namespace
{
	enum class ArgParseResult
	{
		// We don't have enough info to continue linting
		InsufficentInfo,
		// This argument looks suspicious
		SuspiciousArg,
		// It worked
		Success
	};

	enum class ConnectCallType
	{
		Unrecognized,
		StaticFiveArg,
		MemberFourArg
	};

	ConnectCallType exprConnectCallType(const clang::CallExpr *expr)
	{
		// These are needed a lot so keep them around
		static const clang::StringRef expectedMethodName("connect");
		static const clang::StringRef expectedClassName("QObject");
		const unsigned int argCount = expr->getNumArgs();

		const clang::Decl *calleeDecl = expr->getCalleeDecl();

		// Assume this is a method
		const auto *methodDecl = clang::dyn_cast_or_null<clang::CXXMethodDecl>(calleeDecl);

		if (!methodDecl)
		{
			// Nope
			return ConnectCallType::Unrecognized;
		}

		ConnectCallType callType;

		// Figure out what kind of connect call it is
		if (methodDecl->isStatic() && (argCount == 5))
		{
			callType = ConnectCallType::StaticFiveArg;
		}
		else if (!methodDecl->isStatic() && (argCount == 4))
		{
			callType = ConnectCallType::MemberFourArg;
		}
		else
		{
			return ConnectCallType::Unrecognized;
		}

		// Check the name of the class and methond
		if (methodDecl->getName() != expectedMethodName)
		{
			return ConnectCallType::Unrecognized;
		}

		if (methodDecl->getParent()->getName() != expectedClassName)
		{
			return ConnectCallType::Unrecognized;
		}

		return callType;
	}

	const clang::CXXRecordDecl *declForArg(const clang::Expr *rawExpr)
	{
		// connect calls generally have a lot of casting
		const clang::Expr *expr = rawExpr->IgnoreImpCasts();
		return expr->getType().getTypePtr()->getPointeeCXXRecordDecl();
	}

	MetaMethodRef metaMethodRefForArg(const clang::Expr *expr, clang::CompilerInstance &instance, ArgParseResult &parseResult)
	{
		const auto *callExpr = clang::dyn_cast<clang::CallExpr>(expr);

		if (!callExpr)
		{
			// Not a call - it won't be easy to get a static string value for it
			parseResult = ArgParseResult::InsufficentInfo;
			return MetaMethodRef();
		}

		const clang::FunctionDecl *functionDecl = callExpr->getDirectCallee();

		if (!functionDecl || (functionDecl->getName() != clang::StringRef("qFlagLocation")))
		{
			// Not a call to qFlagLocation
			parseResult = ArgParseResult::InsufficentInfo;
			return MetaMethodRef();
		}

		if (callExpr->getNumArgs() != 1)
		{
			// I don't get it
			parseResult = ArgParseResult::SuspiciousArg;
			return MetaMethodRef();
		}

		const auto *stringLiteral = clang::dyn_cast<clang::StringLiteral>(
				callExpr->getArg(0)->IgnoreImpCasts());

		// Use Data() so we chop the location data after the \000
		parseResult = ArgParseResult::Success;
		return MetaMethodRef(stringLiteral->getString().data(), instance);
	}
}

ConnectCall ConnectCall::fromCallExpr(const clang::CallExpr *expr, clang::CompilerInstance &instance)
{
	return ConnectCall(expr, instance);
}

ConnectCall::ConnectCall(const clang::CallExpr *expr, clang::CompilerInstance &instance) :
	mExpr(nullptr)
{
	ConnectCallType callType = exprConnectCallType(expr);
	unsigned int sendMethodArgIndex = 0;
	unsigned int receiveMethodArgIndex = 0;

	if (callType == ConnectCallType::Unrecognized)
	{
		return;
	}
	else if (callType == ConnectCallType::StaticFiveArg)
	{
		mSender = declForArg(expr->getArg(0));
		sendMethodArgIndex = 1;
		mReceiver = declForArg(expr->getArg(2));
		receiveMethodArgIndex = 3;

		if ((mSender == nullptr) || (mReceiver == nullptr))
		{
			return;
		}

	}
	else if (callType == ConnectCallType::MemberFourArg)
	{
		const clang::CXXMemberCallExpr *memberCallExpr = clang::dyn_cast<clang::CXXMemberCallExpr>(expr);

		if (memberCallExpr == nullptr)
		{
			return;
		}

		mReceiver = declForArg(memberCallExpr->getImplicitObjectArgument());
		mSender = declForArg(memberCallExpr->getArg(0));
		sendMethodArgIndex = 1;
		receiveMethodArgIndex = 2;
	}

	// Looks like a connect! Parse the meta method references
	ArgParseResult parseResult;
	mSendMethod = metaMethodRefForArg(expr->getArg(sendMethodArgIndex), instance, parseResult);

	if (parseResult == ArgParseResult::InsufficentInfo)
	{
		return;
	}

	mReceiveMethod = metaMethodRefForArg(expr->getArg(receiveMethodArgIndex), instance, parseResult);

	if (parseResult == ArgParseResult::InsufficentInfo)
	{
		return;
	}

	mExpr = expr;
}
<commit_msg>Support for string literal slot/signal names<commit_after>#include "ConnectCall.h"

#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"

#include "MetaMethodRef.h"

namespace
{
	enum class ArgParseResult
	{
		// We don't have enough info to continue linting
		InsufficentInfo,
		// This argument looks suspicious
		SuspiciousArg,
		// It worked
		Success
	};

	enum class ConnectCallType
	{
		Unrecognized,
		StaticFiveArg,
		MemberFourArg
	};

	ConnectCallType exprConnectCallType(const clang::CallExpr *expr)
	{
		// These are needed a lot so keep them around
		static const clang::StringRef expectedMethodName("connect");
		static const clang::StringRef expectedClassName("QObject");
		const unsigned int argCount = expr->getNumArgs();

		const clang::Decl *calleeDecl = expr->getCalleeDecl();

		// Assume this is a method
		const auto *methodDecl = clang::dyn_cast_or_null<clang::CXXMethodDecl>(calleeDecl);

		if (!methodDecl)
		{
			// Nope
			return ConnectCallType::Unrecognized;
		}

		ConnectCallType callType;

		// Figure out what kind of connect call it is
		if (methodDecl->isStatic() && (argCount == 5))
		{
			callType = ConnectCallType::StaticFiveArg;
		}
		else if (!methodDecl->isStatic() && (argCount == 4))
		{
			callType = ConnectCallType::MemberFourArg;
		}
		else
		{
			return ConnectCallType::Unrecognized;
		}

		// Check the name of the class and methond
		if (methodDecl->getName() != expectedMethodName)
		{
			return ConnectCallType::Unrecognized;
		}

		if (methodDecl->getParent()->getName() != expectedClassName)
		{
			return ConnectCallType::Unrecognized;
		}

		return callType;
	}

	const clang::CXXRecordDecl *declForArg(const clang::Expr *rawExpr)
	{
		// connect calls generally have a lot of casting
		const clang::Expr *expr = rawExpr->IgnoreImpCasts();
		return expr->getType().getTypePtr()->getPointeeCXXRecordDecl();
	}

	MetaMethodRef metaMethodRefForArg(const clang::Expr *expr, clang::CompilerInstance &instance, ArgParseResult &parseResult)
	{
		const clang::StringLiteral *stringLiteral = nullptr;

		if (clang::isa<clang::CallExpr>(expr))
		{
			const auto *callExpr = clang::dyn_cast<clang::CallExpr>(expr);

			const clang::FunctionDecl *functionDecl = callExpr->getDirectCallee();

			if (!functionDecl || (functionDecl->getName() != clang::StringRef("qFlagLocation")))
			{
				// Not a call to qFlagLocation
				parseResult = ArgParseResult::InsufficentInfo;
				return MetaMethodRef();
			}

			if (callExpr->getNumArgs() != 1)
			{
				// I don't get it
				parseResult = ArgParseResult::SuspiciousArg;
				return MetaMethodRef();
			}

			stringLiteral = clang::dyn_cast<clang::StringLiteral>(callExpr->getArg(0)->IgnoreImpCasts());
		}
		else if (clang::isa<clang::StringLiteral>(expr->IgnoreImpCasts()))
		{
			// This is a direct string literal
			stringLiteral = clang::dyn_cast<clang::StringLiteral>(expr->IgnoreImpCasts());
		}
		else
		{
			// Not sure what this is - it won't be easy to get a static string value for it
			parseResult = ArgParseResult::InsufficentInfo;
			return MetaMethodRef();
		}

		parseResult = ArgParseResult::Success;

		std::string methodDataStr = stringLiteral->getString().str();

		// Chop everything off after the first \0 - qFlagLocation encodes the location after that
		size_t nullPos = methodDataStr.find('\0');

		if (nullPos != std::string::npos)
		{
			methodDataStr.resize(nullPos);
		}

		return MetaMethodRef(methodDataStr, instance);
	}
}

ConnectCall ConnectCall::fromCallExpr(const clang::CallExpr *expr, clang::CompilerInstance &instance)
{
	return ConnectCall(expr, instance);
}

ConnectCall::ConnectCall(const clang::CallExpr *expr, clang::CompilerInstance &instance) :
	mExpr(nullptr)
{
	ConnectCallType callType = exprConnectCallType(expr);
	unsigned int sendMethodArgIndex = 0;
	unsigned int receiveMethodArgIndex = 0;

	if (callType == ConnectCallType::Unrecognized)
	{
		return;
	}
	else if (callType == ConnectCallType::StaticFiveArg)
	{
		mSender = declForArg(expr->getArg(0));
		sendMethodArgIndex = 1;
		mReceiver = declForArg(expr->getArg(2));
		receiveMethodArgIndex = 3;

		if ((mSender == nullptr) || (mReceiver == nullptr))
		{
			return;
		}

	}
	else if (callType == ConnectCallType::MemberFourArg)
	{
		const clang::CXXMemberCallExpr *memberCallExpr = clang::dyn_cast<clang::CXXMemberCallExpr>(expr);

		if (memberCallExpr == nullptr)
		{
			return;
		}

		mReceiver = declForArg(memberCallExpr->getImplicitObjectArgument());
		mSender = declForArg(memberCallExpr->getArg(0));
		sendMethodArgIndex = 1;
		receiveMethodArgIndex = 2;
	}

	// Looks like a connect! Parse the meta method references
	ArgParseResult parseResult;
	mSendMethod = metaMethodRefForArg(expr->getArg(sendMethodArgIndex), instance, parseResult);

	if (parseResult == ArgParseResult::InsufficentInfo)
	{
		return;
	}

	mReceiveMethod = metaMethodRefForArg(expr->getArg(receiveMethodArgIndex), instance, parseResult);

	if (parseResult == ArgParseResult::InsufficentInfo)
	{
		return;
	}

	mExpr = expr;
}
<|endoftext|>


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

#include "chrome/installer/util/master_preferences.h"

#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "chrome/common/json_value_serializer.h"
#include "chrome/installer/util/master_preferences_constants.h"
#include "chrome/installer/util/util_constants.h"
#include "googleurl/src/gurl.h"

namespace {

const char kDistroDict[] = "distribution";
const char kFirstRunTabs[] = "first_run_tabs";

bool GetGURLFromValue(const Value* in_value, GURL* out_value) {
  if (!in_value || !out_value)
    return false;
  std::string url;
  in_value->GetAsString(&url);
  GURL gurl(url);
  *out_value = gurl;
  return true;
}

std::vector<GURL> GetNamedList(const char* name,
                               const DictionaryValue* prefs) {
  std::vector<GURL> list;
  if (!prefs)
    return list;
  ListValue* value_list = NULL;
  if (!prefs->GetList(name, &value_list))
    return list;
  for (size_t i = 0; i < value_list->GetSize(); ++i) {
    Value* entry;
    GURL gurl_entry;
    if (!value_list->Get(i, &entry) || !GetGURLFromValue(entry, &gurl_entry)) {
      NOTREACHED();
      break;
    }
    list.push_back(gurl_entry);
  }
  return list;
}

DictionaryValue* ParseDistributionPreferences(
    const FilePath& master_prefs_path) {
  std::string json_data;
  if (!file_util::ReadFileToString(master_prefs_path, &json_data)) {
    LOG(WARNING) << "Failed to read master prefs file. ";
    return NULL;
  }
  JSONStringValueSerializer json(json_data);
  std::string error;
  scoped_ptr<Value> root(json.Deserialize(NULL, &error));
  if (!root.get()) {
    LOG(WARNING) << "Failed to parse master prefs file: " << error;
    return NULL;
  }
  if (!root->IsType(Value::TYPE_DICTIONARY)) {
    LOG(WARNING) << "Failed to parse master prefs file: "
                 << "Root item must be a dictionary.";
    return NULL;
  }
  return static_cast<DictionaryValue*>(root.release());
}

}  // namespace

namespace installer_util {

MasterPreferences::MasterPreferences(const CommandLine& cmd_line)
    : distribution_(NULL), preferences_read_from_file_(false) {
#if defined(OS_WIN)
  if (cmd_line.HasSwitch(installer_util::switches::kInstallerData)) {
    FilePath prefs_path(cmd_line.GetSwitchValuePath(
        installer_util::switches::kInstallerData));
    this->MasterPreferences::MasterPreferences(prefs_path);
  } else {
    master_dictionary_.reset(new DictionaryValue());
  }

  DCHECK(master_dictionary_.get());

  // A simple map from command line switches to equivalent switches in the
  // distribution dictionary.  Currently all switches added will be set to
  // 'true'.
  static const struct CmdLineSwitchToDistributionSwitch {
    const wchar_t* cmd_line_switch;
    const char* distribution_switch;
  } translate_switches[] = {
    { installer_util::switches::kChromeFrame,
      installer_util::master_preferences::kChromeFrame },
    { installer_util::switches::kCreateAllShortcuts,
      installer_util::master_preferences::kCreateAllShortcuts },
    { installer_util::switches::kDoNotCreateShortcuts,
      installer_util::master_preferences::kDoNotCreateShortcuts },
    { installer_util::switches::kMsi,
      installer_util::master_preferences::kMsi },
    { installer_util::switches::kDoNotRegisterForUpdateLaunch,
      installer_util::master_preferences::kDoNotRegisterForUpdateLaunch },
    { installer_util::switches::kDoNotLaunchChrome,
      installer_util::master_preferences::kDoNotLaunchChrome },
    { installer_util::switches::kMakeChromeDefault,
      installer_util::master_preferences::kMakeChromeDefault },
    { installer_util::switches::kSystemLevel,
      installer_util::master_preferences::kSystemLevel },
    { installer_util::switches::kVerboseLogging,
      installer_util::master_preferences::kVerboseLogging },
    { installer_util::switches::kAltDesktopShortcut,
      installer_util::master_preferences::kAltShortcutText },
  };

  std::string name(kDistroDict);
  for (int i = 0; i < arraysize(translate_switches); ++i) {
    if (cmd_line.HasSwitch(translate_switches[i].cmd_line_switch)) {
      name.resize(arraysize(kDistroDict) - 1);
      name.append(".").append(translate_switches[i].distribution_switch);
      master_dictionary_->SetBoolean(name, true);
    }
  }

  // Cache a pointer to the distribution dictionary. Ignore errors if any.
  master_dictionary_->GetDictionary(kDistroDict, &distribution_);
#endif
}

MasterPreferences::MasterPreferences(const FilePath& prefs_path)
    : distribution_(NULL), preferences_read_from_file_(false) {
  master_dictionary_.reset(ParseDistributionPreferences(prefs_path));
  LOG_IF(ERROR, !master_dictionary_.get()) << "Failed to parse "
      << prefs_path.value();
  if (!master_dictionary_.get()) {
    master_dictionary_.reset(new DictionaryValue());
  } else {
    preferences_read_from_file_ = true;
    // Cache a pointer to the distribution dictionary.
    master_dictionary_->GetDictionary(kDistroDict, &distribution_);
  }
}

MasterPreferences::~MasterPreferences() {
}

bool MasterPreferences::GetBool(const std::string& name, bool* value) const {
  bool ret = false;
  if (distribution_)
    ret = distribution_->GetBoolean(name, value);
  return ret;
}

bool MasterPreferences::GetInt(const std::string& name, int* value) const {
  bool ret = false;
  if (distribution_)
    ret = distribution_->GetInteger(name, value);
  return ret;
}

bool MasterPreferences::GetString(const std::string& name,
                                  std::string* value) const {
  bool ret = false;
  if (distribution_)
    ret = (distribution_->GetString(name, value) && !value->empty());
  return ret;
}

std::vector<GURL> MasterPreferences::GetFirstRunTabs() const {
  return GetNamedList(kFirstRunTabs, master_dictionary_.get());
}

bool MasterPreferences::GetExtensionsBlock(DictionaryValue** extensions) const {
  return master_dictionary_->GetDictionary(
      master_preferences::kExtensionsBlock, extensions);
}

}  // installer_util
<commit_msg>Preferences: remove log spam.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/installer/util/master_preferences.h"

#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "chrome/common/json_value_serializer.h"
#include "chrome/installer/util/master_preferences_constants.h"
#include "chrome/installer/util/util_constants.h"
#include "googleurl/src/gurl.h"

namespace {

const char kDistroDict[] = "distribution";
const char kFirstRunTabs[] = "first_run_tabs";

bool GetGURLFromValue(const Value* in_value, GURL* out_value) {
  if (!in_value || !out_value)
    return false;
  std::string url;
  in_value->GetAsString(&url);
  GURL gurl(url);
  *out_value = gurl;
  return true;
}

std::vector<GURL> GetNamedList(const char* name,
                               const DictionaryValue* prefs) {
  std::vector<GURL> list;
  if (!prefs)
    return list;
  ListValue* value_list = NULL;
  if (!prefs->GetList(name, &value_list))
    return list;
  for (size_t i = 0; i < value_list->GetSize(); ++i) {
    Value* entry;
    GURL gurl_entry;
    if (!value_list->Get(i, &entry) || !GetGURLFromValue(entry, &gurl_entry)) {
      NOTREACHED();
      break;
    }
    list.push_back(gurl_entry);
  }
  return list;
}

DictionaryValue* ParseDistributionPreferences(
    const FilePath& master_prefs_path) {
  std::string json_data;
  if (!file_util::ReadFileToString(master_prefs_path, &json_data))
    return NULL;

  JSONStringValueSerializer json(json_data);
  std::string error;
  scoped_ptr<Value> root(json.Deserialize(NULL, &error));
  if (!root.get()) {
    LOG(WARNING) << "Failed to parse master prefs file: " << error;
    return NULL;
  }
  if (!root->IsType(Value::TYPE_DICTIONARY)) {
    LOG(WARNING) << "Failed to parse master prefs file: "
                 << "Root item must be a dictionary.";
    return NULL;
  }
  return static_cast<DictionaryValue*>(root.release());
}

}  // namespace

namespace installer_util {

MasterPreferences::MasterPreferences(const CommandLine& cmd_line)
    : distribution_(NULL), preferences_read_from_file_(false) {
#if defined(OS_WIN)
  if (cmd_line.HasSwitch(installer_util::switches::kInstallerData)) {
    FilePath prefs_path(cmd_line.GetSwitchValuePath(
        installer_util::switches::kInstallerData));
    this->MasterPreferences::MasterPreferences(prefs_path);
  } else {
    master_dictionary_.reset(new DictionaryValue());
  }

  DCHECK(master_dictionary_.get());

  // A simple map from command line switches to equivalent switches in the
  // distribution dictionary.  Currently all switches added will be set to
  // 'true'.
  static const struct CmdLineSwitchToDistributionSwitch {
    const wchar_t* cmd_line_switch;
    const char* distribution_switch;
  } translate_switches[] = {
    { installer_util::switches::kChromeFrame,
      installer_util::master_preferences::kChromeFrame },
    { installer_util::switches::kCreateAllShortcuts,
      installer_util::master_preferences::kCreateAllShortcuts },
    { installer_util::switches::kDoNotCreateShortcuts,
      installer_util::master_preferences::kDoNotCreateShortcuts },
    { installer_util::switches::kMsi,
      installer_util::master_preferences::kMsi },
    { installer_util::switches::kDoNotRegisterForUpdateLaunch,
      installer_util::master_preferences::kDoNotRegisterForUpdateLaunch },
    { installer_util::switches::kDoNotLaunchChrome,
      installer_util::master_preferences::kDoNotLaunchChrome },
    { installer_util::switches::kMakeChromeDefault,
      installer_util::master_preferences::kMakeChromeDefault },
    { installer_util::switches::kSystemLevel,
      installer_util::master_preferences::kSystemLevel },
    { installer_util::switches::kVerboseLogging,
      installer_util::master_preferences::kVerboseLogging },
    { installer_util::switches::kAltDesktopShortcut,
      installer_util::master_preferences::kAltShortcutText },
  };

  std::string name(kDistroDict);
  for (int i = 0; i < arraysize(translate_switches); ++i) {
    if (cmd_line.HasSwitch(translate_switches[i].cmd_line_switch)) {
      name.resize(arraysize(kDistroDict) - 1);
      name.append(".").append(translate_switches[i].distribution_switch);
      master_dictionary_->SetBoolean(name, true);
    }
  }

  // Cache a pointer to the distribution dictionary. Ignore errors if any.
  master_dictionary_->GetDictionary(kDistroDict, &distribution_);
#endif
}

MasterPreferences::MasterPreferences(const FilePath& prefs_path)
    : distribution_(NULL), preferences_read_from_file_(false) {
  master_dictionary_.reset(ParseDistributionPreferences(prefs_path));

  if (!master_dictionary_.get()) {
    master_dictionary_.reset(new DictionaryValue());
  } else {
    preferences_read_from_file_ = true;
    // Cache a pointer to the distribution dictionary.
    master_dictionary_->GetDictionary(kDistroDict, &distribution_);
  }
}

MasterPreferences::~MasterPreferences() {
}

bool MasterPreferences::GetBool(const std::string& name, bool* value) const {
  bool ret = false;
  if (distribution_)
    ret = distribution_->GetBoolean(name, value);
  return ret;
}

bool MasterPreferences::GetInt(const std::string& name, int* value) const {
  bool ret = false;
  if (distribution_)
    ret = distribution_->GetInteger(name, value);
  return ret;
}

bool MasterPreferences::GetString(const std::string& name,
                                  std::string* value) const {
  bool ret = false;
  if (distribution_)
    ret = (distribution_->GetString(name, value) && !value->empty());
  return ret;
}

std::vector<GURL> MasterPreferences::GetFirstRunTabs() const {
  return GetNamedList(kFirstRunTabs, master_dictionary_.get());
}

bool MasterPreferences::GetExtensionsBlock(DictionaryValue** extensions) const {
  return master_dictionary_->GetDictionary(
      master_preferences::kExtensionsBlock, extensions);
}

}  // installer_util
<|endoftext|>