<commit_before>//===--- ManagedValue.cpp - Value with cleanup ----------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// A storage structure for holding a destructured rvalue with an optional
// cleanup(s).
// Ownership of the rvalue can be "forwarded" to disable the associated
// cleanup(s).
//
//===----------------------------------------------------------------------===//

#include "ManagedValue.h"
#include "SILGenFunction.h"
using namespace swift;
using namespace Lowering;

/// Emit a copy of this value with independent ownership.
ManagedValue ManagedValue::copy(SILGenFunction &SGF, SILLocation loc) const {
  auto &lowering = SGF.getTypeLowering(getType());
  if (lowering.isTrivial())
    return *this;

  if (getType().isObject()) {
    return SGF.B.createCopyValue(loc, *this, lowering);
  }

  SILValue buf = SGF.emitTemporaryAllocation(loc, getType());
  SGF.B.createCopyAddr(loc, getValue(), buf, IsNotTake, IsInitialization);
  return SGF.emitManagedRValueWithCleanup(buf, lowering);
}

/// Emit a copy of this value with independent ownership.
ManagedValue ManagedValue::formalAccessCopy(SILGenFunction &SGF,
                                            SILLocation loc) {
  assert(SGF.InFormalEvaluationScope && "Can only perform a formal access copy in a "
                                 "formal evaluation scope");
  auto &lowering = SGF.getTypeLowering(getType());
  if (lowering.isTrivial())
    return *this;

  if (getType().isObject()) {
    return SGF.B.createFormalAccessCopyValue(loc, *this);
  }

  SILValue buf = SGF.emitTemporaryAllocation(loc, getType());
  return SGF.B.createFormalAccessCopyAddr(loc, *this, buf, IsNotTake,
                                          IsInitialization);
}

/// Store a copy of this value with independent ownership into the given
/// uninitialized address.
void ManagedValue::copyInto(SILGenFunction &SGF, SILValue dest,
                            SILLocation loc) {
  auto &lowering = SGF.getTypeLowering(getType());
  if (lowering.isAddressOnly() && SGF.silConv.useLoweredAddresses()) {
    SGF.B.createCopyAddr(loc, getValue(), dest, IsNotTake, IsInitialization);
    return;
  }

  SILValue copy = lowering.emitCopyValue(SGF.B, loc, getValue());
  lowering.emitStoreOfCopy(SGF.B, loc, copy, dest, IsInitialization);
}

/// This is the same operation as 'copy', but works on +0 values that don't
/// have cleanups.  It returns a +1 value with one.
ManagedValue ManagedValue::copyUnmanaged(SILGenFunction &SGF, SILLocation loc) {
  if (getType().isObject()) {
    return SGF.B.createCopyValue(loc, *this);
  }

  SILValue result = SGF.emitTemporaryAllocation(loc, getType());
  SGF.B.createCopyAddr(loc, getValue(), result, IsNotTake, IsInitialization);
  return SGF.emitManagedRValueWithCleanup(result);
}

/// This is the same operation as 'copy', but works on +0 values that don't
/// have cleanups.  It returns a +1 value with one.
ManagedValue ManagedValue::formalAccessCopyUnmanaged(SILGenFunction &SGF,
                                                     SILLocation loc) {
  if (getType().isObject()) {
    return SGF.B.createFormalAccessCopyValue(loc, *this);
  }

  SILValue result = SGF.emitTemporaryAllocation(loc, getType());
  return SGF.B.createFormalAccessCopyAddr(loc, *this, result, IsNotTake,
                                          IsInitialization);
}

/// Disable the cleanup for this value.
void ManagedValue::forwardCleanup(SILGenFunction &SGF) const {
  assert(hasCleanup() && "value doesn't have cleanup!");
  SGF.Cleanups.forwardCleanup(getCleanup());
}

/// Forward this value, deactivating the cleanup and returning the
/// underlying value.
SILValue ManagedValue::forward(SILGenFunction &SGF) const {
  if (hasCleanup())
    forwardCleanup(SGF);
  return getValue();
}

void ManagedValue::forwardInto(SILGenFunction &SGF, SILLocation loc,
                               SILValue address) {
  if (!hasCleanup() && getOwnershipKind() != ValueOwnershipKind::Trivial)
    return copyUnmanaged(SGF, loc).forwardInto(SGF, loc, address);

  if (hasCleanup())
    forwardCleanup(SGF);

  auto &addrTL = SGF.getTypeLowering(address->getType());
  SGF.emitSemanticStore(loc, getValue(), address,
                        addrTL, IsInitialization);
}

void ManagedValue::assignInto(SILGenFunction &SGF, SILLocation loc,
                              SILValue address) {
  if (hasCleanup())
    forwardCleanup(SGF);

  auto &addrTL = SGF.getTypeLowering(address->getType());
  SGF.emitSemanticStore(loc, getValue(), address, addrTL,
                        IsNotInitialization);
}

void ManagedValue::forwardInto(SILGenFunction &SGF, SILLocation loc,
                               Initialization *dest) {
  dest->copyOrInitValueInto(SGF, loc, *this, /*isInit*/ true);
  dest->finishInitialization(SGF);
}

ManagedValue ManagedValue::borrow(SILGenFunction &SGF, SILLocation loc) const {
  assert(getValue() && "cannot borrow an invalid or in-context value");
  if (isLValue())
    return *this;
  if (getType().isAddress())
    return ManagedValue::forUnmanaged(getValue());
  return SGF.emitManagedBeginBorrow(loc, getValue());
}

ManagedValue ManagedValue::formalAccessBorrow(SILGenFunction &SGF,
                                              SILLocation loc) const {
  assert(getValue() && "cannot borrow an invalid or in-context value");
  if (isLValue())
    return *this;
  if (getType().isAddress())
    return ManagedValue::forUnmanaged(getValue());
  return SGF.emitFormalEvaluationManagedBeginBorrow(loc, getValue());
}

ManagedValue ManagedValue::materialize(SILGenFunction &SGF,
                                       SILLocation loc) const {
  auto temporary = SGF.emitTemporaryAllocation(loc, getType());
  bool hadCleanup = hasCleanup();

  // The temporary memory is +0 if the value was.
  if (hadCleanup) {
    SGF.B.emitStoreValueOperation(loc, forward(SGF), temporary,
                                  StoreOwnershipQualifier::Init);

    // SEMANTIC SIL TODO: This should really be called a temporary LValue.
    return ManagedValue::forOwnedAddressRValue(temporary,
                                          SGF.enterDestroyCleanup(temporary));
  } else {
    auto object = SGF.emitManagedBeginBorrow(loc, getValue());
    SGF.emitManagedStoreBorrow(loc, object.getValue(), temporary);
    return ManagedValue::forBorrowedAddressRValue(temporary);
  }
}

void ManagedValue::print(raw_ostream &os) const {
  if (SILValue v = getValue()) {
    v->print(os);
  }
}

void ManagedValue::dump() const {
  dump(llvm::errs());
}

void ManagedValue::dump(raw_ostream &os, unsigned indent) const {
  os.indent(indent);
  if (isInContext()) {
    os << "InContext\n";
    return;
  }
  if (isLValue()) os << "[lvalue] ";
  if (hasCleanup()) os << "[cleanup] ";
  if (SILValue v = getValue()) {
    v->print(os);
  } else {
    os << "<null>\n";
  }
}

ManagedValue ManagedValue::ensurePlusOne(SILGenFunction &SGF,
                                         SILLocation loc) const {
  // guaranteed-normal-args-todo: We only copy here when guaranteed normal args
  // are explicitly enabled. Otherwise, this always just returns self.
  if (SGF.getOptions().EnableGuaranteedNormalArguments && !hasCleanup()) {
    return copy(SGF, loc);
  }
  return *this;
}
<commit_msg>[silgen] Make ensurePlusOne emit copies even when guaranteed normal arguments is not enabled.<commit_after>//===--- ManagedValue.cpp - Value with cleanup ----------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// A storage structure for holding a destructured rvalue with an optional
// cleanup(s).
// Ownership of the rvalue can be "forwarded" to disable the associated
// cleanup(s).
//
//===----------------------------------------------------------------------===//

#include "ManagedValue.h"
#include "SILGenFunction.h"
using namespace swift;
using namespace Lowering;

/// Emit a copy of this value with independent ownership.
ManagedValue ManagedValue::copy(SILGenFunction &SGF, SILLocation loc) const {
  auto &lowering = SGF.getTypeLowering(getType());
  if (lowering.isTrivial())
    return *this;

  if (getType().isObject()) {
    return SGF.B.createCopyValue(loc, *this, lowering);
  }

  SILValue buf = SGF.emitTemporaryAllocation(loc, getType());
  SGF.B.createCopyAddr(loc, getValue(), buf, IsNotTake, IsInitialization);
  return SGF.emitManagedRValueWithCleanup(buf, lowering);
}

/// Emit a copy of this value with independent ownership.
ManagedValue ManagedValue::formalAccessCopy(SILGenFunction &SGF,
                                            SILLocation loc) {
  assert(SGF.InFormalEvaluationScope && "Can only perform a formal access copy in a "
                                 "formal evaluation scope");
  auto &lowering = SGF.getTypeLowering(getType());
  if (lowering.isTrivial())
    return *this;

  if (getType().isObject()) {
    return SGF.B.createFormalAccessCopyValue(loc, *this);
  }

  SILValue buf = SGF.emitTemporaryAllocation(loc, getType());
  return SGF.B.createFormalAccessCopyAddr(loc, *this, buf, IsNotTake,
                                          IsInitialization);
}

/// Store a copy of this value with independent ownership into the given
/// uninitialized address.
void ManagedValue::copyInto(SILGenFunction &SGF, SILValue dest,
                            SILLocation loc) {
  auto &lowering = SGF.getTypeLowering(getType());
  if (lowering.isAddressOnly() && SGF.silConv.useLoweredAddresses()) {
    SGF.B.createCopyAddr(loc, getValue(), dest, IsNotTake, IsInitialization);
    return;
  }

  SILValue copy = lowering.emitCopyValue(SGF.B, loc, getValue());
  lowering.emitStoreOfCopy(SGF.B, loc, copy, dest, IsInitialization);
}

/// This is the same operation as 'copy', but works on +0 values that don't
/// have cleanups.  It returns a +1 value with one.
ManagedValue ManagedValue::copyUnmanaged(SILGenFunction &SGF, SILLocation loc) {
  if (getType().isObject()) {
    return SGF.B.createCopyValue(loc, *this);
  }

  SILValue result = SGF.emitTemporaryAllocation(loc, getType());
  SGF.B.createCopyAddr(loc, getValue(), result, IsNotTake, IsInitialization);
  return SGF.emitManagedRValueWithCleanup(result);
}

/// This is the same operation as 'copy', but works on +0 values that don't
/// have cleanups.  It returns a +1 value with one.
ManagedValue ManagedValue::formalAccessCopyUnmanaged(SILGenFunction &SGF,
                                                     SILLocation loc) {
  if (getType().isObject()) {
    return SGF.B.createFormalAccessCopyValue(loc, *this);
  }

  SILValue result = SGF.emitTemporaryAllocation(loc, getType());
  return SGF.B.createFormalAccessCopyAddr(loc, *this, result, IsNotTake,
                                          IsInitialization);
}

/// Disable the cleanup for this value.
void ManagedValue::forwardCleanup(SILGenFunction &SGF) const {
  assert(hasCleanup() && "value doesn't have cleanup!");
  SGF.Cleanups.forwardCleanup(getCleanup());
}

/// Forward this value, deactivating the cleanup and returning the
/// underlying value.
SILValue ManagedValue::forward(SILGenFunction &SGF) const {
  if (hasCleanup())
    forwardCleanup(SGF);
  return getValue();
}

void ManagedValue::forwardInto(SILGenFunction &SGF, SILLocation loc,
                               SILValue address) {
  if (!hasCleanup() && getOwnershipKind() != ValueOwnershipKind::Trivial)
    return copyUnmanaged(SGF, loc).forwardInto(SGF, loc, address);

  if (hasCleanup())
    forwardCleanup(SGF);

  auto &addrTL = SGF.getTypeLowering(address->getType());
  SGF.emitSemanticStore(loc, getValue(), address,
                        addrTL, IsInitialization);
}

void ManagedValue::assignInto(SILGenFunction &SGF, SILLocation loc,
                              SILValue address) {
  if (hasCleanup())
    forwardCleanup(SGF);

  auto &addrTL = SGF.getTypeLowering(address->getType());
  SGF.emitSemanticStore(loc, getValue(), address, addrTL,
                        IsNotInitialization);
}

void ManagedValue::forwardInto(SILGenFunction &SGF, SILLocation loc,
                               Initialization *dest) {
  dest->copyOrInitValueInto(SGF, loc, *this, /*isInit*/ true);
  dest->finishInitialization(SGF);
}

ManagedValue ManagedValue::borrow(SILGenFunction &SGF, SILLocation loc) const {
  assert(getValue() && "cannot borrow an invalid or in-context value");
  if (isLValue())
    return *this;
  if (getType().isAddress())
    return ManagedValue::forUnmanaged(getValue());
  return SGF.emitManagedBeginBorrow(loc, getValue());
}

ManagedValue ManagedValue::formalAccessBorrow(SILGenFunction &SGF,
                                              SILLocation loc) const {
  assert(getValue() && "cannot borrow an invalid or in-context value");
  if (isLValue())
    return *this;
  if (getType().isAddress())
    return ManagedValue::forUnmanaged(getValue());
  return SGF.emitFormalEvaluationManagedBeginBorrow(loc, getValue());
}

ManagedValue ManagedValue::materialize(SILGenFunction &SGF,
                                       SILLocation loc) const {
  auto temporary = SGF.emitTemporaryAllocation(loc, getType());
  bool hadCleanup = hasCleanup();

  // The temporary memory is +0 if the value was.
  if (hadCleanup) {
    SGF.B.emitStoreValueOperation(loc, forward(SGF), temporary,
                                  StoreOwnershipQualifier::Init);

    // SEMANTIC SIL TODO: This should really be called a temporary LValue.
    return ManagedValue::forOwnedAddressRValue(temporary,
                                          SGF.enterDestroyCleanup(temporary));
  } else {
    auto object = SGF.emitManagedBeginBorrow(loc, getValue());
    SGF.emitManagedStoreBorrow(loc, object.getValue(), temporary);
    return ManagedValue::forBorrowedAddressRValue(temporary);
  }
}

void ManagedValue::print(raw_ostream &os) const {
  if (SILValue v = getValue()) {
    v->print(os);
  }
}

void ManagedValue::dump() const {
  dump(llvm::errs());
}

void ManagedValue::dump(raw_ostream &os, unsigned indent) const {
  os.indent(indent);
  if (isInContext()) {
    os << "InContext\n";
    return;
  }
  if (isLValue()) os << "[lvalue] ";
  if (hasCleanup()) os << "[cleanup] ";
  if (SILValue v = getValue()) {
    v->print(os);
  } else {
    os << "<null>\n";
  }
}

ManagedValue ManagedValue::ensurePlusOne(SILGenFunction &SGF,
                                         SILLocation loc) const {
  if (!hasCleanup()) {
    return copy(SGF, loc);
  }
  return *this;
}
<|endoftext|>


<commit_before>#include "iotsaApi.h"
#ifdef IOTSA_WITH_COAP
#include <WiFiUdp.h>
#include <coap-simple.h>

#define COAP_PROTOCOL_DEBUG

// Static variable
IotsaCoapServiceMod* IotsaCoapApiService::_coapMod = NULL;

class CoapEndpoint {
public:
  CoapEndpoint(IotsaApiProvider *_provider, const char *_path, bool _get, bool _put, bool _post)
  : provider(_provider),
    path(_path),
    get(_get),
    put(_put),
    post(_post),
    next(NULL),
    coap(NULL)
  {}
  IotsaApiProvider *provider;
  const char *path;
  bool get;
  bool put;
  bool post;
  CoapEndpoint *next;
  Coap* coap;
  CoapCallback getCallback(Coap *_coap);
  void callbackImpl(CoapPacket &pkt, IPAddress ip, int port);

};

CoapCallback CoapEndpoint::getCallback(Coap *_coap) {
    coap = _coap;
    return std::bind(&CoapEndpoint::callbackImpl, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
}

void CoapEndpoint::callbackImpl(CoapPacket &pkt, IPAddress ip, int port) {
#ifdef COAP_PROTOCOL_DEBUG
    IotsaSerial.print("COAP pkt recvd from "); IotsaSerial.print(ip); IotsaSerial.print(" port "); IotsaSerial.println(port);
    IotsaSerial.print("type "); IotsaSerial.println(int(pkt.type));
    IotsaSerial.print("code "); IotsaSerial.println(int(pkt.code));
    IotsaSerial.print("tokenlen "); IotsaSerial.println(int(pkt.tokenlen));
    IotsaSerial.print("payloadlen "); IotsaSerial.println(int(pkt.payloadlen));
    IotsaSerial.print("messageid "); IotsaSerial.println(int(pkt.messageid));
    IotsaSerial.print("optionnum "); IotsaSerial.println(int(pkt.optionnum));
#endif
    bool ok = false;
    String replyData;
    // Handle requests, after chaing that type (get/put/post) is supported.
    if (pkt.code == COAP_GET) {
        IFDEBUG IotsaSerial.print("COAP-GET api ");
        IFDEBUG IotsaSerial.println(path);
        ok = get;
        if (ok) {
            DynamicJsonDocument replyDocument(2048);
            JsonObject reply = replyDocument.to<JsonObject>();
            ok = provider->getHandler(path, reply);
            if (ok) {
                serializeJson(replyDocument, replyData);
            }
        }
    } else
    if (pkt.code == COAP_PUT) {
        IFDEBUG IotsaSerial.print("COAP-PUT api ");
        IFDEBUG IotsaSerial.println(path);
        ok = put;
        // xxxjack Should look through pkt.options looking for mimetype=application/json
        if (ok) {
            char dataBuffer[pkt.payloadlen+1];
            memcpy(dataBuffer, pkt.payload, pkt.payloadlen);
            dataBuffer[pkt.payloadlen] = 0;
#ifdef COAP_PROTOCOL_DEBUG
            IotsaSerial.print("payload "); IotsaSerial.println(dataBuffer);
#endif
            DynamicJsonDocument requestDocument(2048);
            deserializeJson(requestDocument, dataBuffer);
            DynamicJsonDocument replyDocument(2048);
            JsonObject request = requestDocument.as<JsonObject>();
            JsonObject reply = replyDocument.to<JsonObject>();

            ok = provider->putHandler(path, request, reply);
            if (ok) {
                serializeJson(replyDocument, replyData);
            }
        }
    } else
    if (pkt.code == COAP_POST) {
        IFDEBUG IotsaSerial.print("COAP-POST api ");
        IFDEBUG IotsaSerial.println(path);
        ok = post;
        // xxxjack Should look through pkt.options looking for mimetype=application/json
        if (ok) {
            char dataBuffer[pkt.payloadlen+1];
            memcpy(dataBuffer, pkt.payload, pkt.payloadlen);
            dataBuffer[pkt.payloadlen] = 0;
#ifdef COAP_PROTOCOL_DEBUG
            IotsaSerial.print("payload "); IotsaSerial.println(dataBuffer);
#endif
            DynamicJsonDocument requestDocument(2048);
            deserializeJson(requestDocument, dataBuffer);
            DynamicJsonDocument replyDocument(2048);
            JsonObject request = requestDocument.as<JsonObject>();
            JsonObject reply = replyDocument.to<JsonObject>();
            ok = provider->postHandler(path, request, reply);
            if (ok) {
                serializeJson(replyDocument, replyData);
            }
        }
    } else {
        IFDEBUG IotsaSerial.print("COAP-UNKNOWN ");
        IFDEBUG IotsaSerial.println(int(pkt.code));
    }
    // Send reply, either a JSON datastructure or an error.
    if (ok) {
#ifdef COAP_PROTOCOL_DEBUG
        IotsaSerial.print("replyData "); IotsaSerial.println(replyData);
        IotsaSerial.print("replyLen "); IotsaSerial.println(replyData.length());
#endif
        int rv = coap->sendResponse(ip, port, pkt.messageid, replyData.c_str(), replyData.length(), COAP_CONTENT, COAP_APPLICATION_JSON, NULL, 0);
        if (rv) {
            IFDEBUG IotsaSerial.println("-> OK");
        } else {
            coap->sendResponse(ip, port, pkt.messageid, NULL, 0, COAP_INTERNAL_SERVER_ERROR, COAP_NONE, NULL, 0);
            IotsaSerial.println("-> xmitReplyError");
        }
    } else {
        coap->sendResponse(ip, port, pkt.messageid, NULL, 0, COAP_BAD_REQUEST, COAP_NONE, NULL, 0);
        IFDEBUG IotsaSerial.println("-> ERR");
    }
    delay(2000); // xxxjack
}

class IotsaCoapServiceMod : public IotsaBaseMod {
public:
  IotsaCoapServiceMod(IotsaApplication &_app);
  void setup();
  void loop();
  void addEndpoint(CoapEndpoint *ep, const char *path);
protected:
  CoapEndpoint *firstEndpoint;
  WiFiUDP udp;
  Coap coap;
};

IotsaCoapServiceMod::IotsaCoapServiceMod(IotsaApplication &_app)
  : IotsaBaseMod(_app),
    firstEndpoint(NULL),
    udp(),
    coap(udp)
  {}

void IotsaCoapServiceMod::setup() {
    if (!iotsaConfig.wifiEnabled) return;
    coap.start();
}

void IotsaCoapServiceMod::loop() {
    if (!iotsaConfig.wifiEnabled) return;
    coap.loop();
}

void IotsaCoapServiceMod::addEndpoint(CoapEndpoint *ep, const char *path) {
    if (!iotsaConfig.wifiEnabled) return;
    ep->next = firstEndpoint;
    firstEndpoint = ep;
    coap.server(ep->getCallback(&coap), String(path));
}

IotsaCoapApiService::IotsaCoapApiService(IotsaApiProvider* _provider, IotsaApplication &_app)
  : provider(_provider)
{
  if (_coapMod == NULL) _coapMod = new IotsaCoapServiceMod(_app);
}

void IotsaCoapApiService::setup(const char* path, bool get, bool put, bool post) {
    if (!iotsaConfig.wifiEnabled) return;
    CoapEndpoint *ep = new CoapEndpoint(provider, path, get, put, post);
    if (strncmp(path, "/api/", 5) == 0) path += 5;
    _coapMod->addEndpoint(ep, path);
}

#endif<commit_msg>Coap response didn't include token. Fixed.<commit_after>#include "iotsaApi.h"
#ifdef IOTSA_WITH_COAP
#include <WiFiUdp.h>
#include <coap-simple.h>

#define COAP_PROTOCOL_DEBUG

// Static variable
IotsaCoapServiceMod* IotsaCoapApiService::_coapMod = NULL;

class CoapEndpoint {
public:
  CoapEndpoint(IotsaApiProvider *_provider, const char *_path, bool _get, bool _put, bool _post)
  : provider(_provider),
    path(_path),
    get(_get),
    put(_put),
    post(_post),
    next(NULL),
    coap(NULL)
  {}
  IotsaApiProvider *provider;
  const char *path;
  bool get;
  bool put;
  bool post;
  CoapEndpoint *next;
  Coap* coap;
  CoapCallback getCallback(Coap *_coap);
  void callbackImpl(CoapPacket &pkt, IPAddress ip, int port);

};

CoapCallback CoapEndpoint::getCallback(Coap *_coap) {
    coap = _coap;
    return std::bind(&CoapEndpoint::callbackImpl, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
}

void CoapEndpoint::callbackImpl(CoapPacket &pkt, IPAddress ip, int port) {
#ifdef COAP_PROTOCOL_DEBUG
    IotsaSerial.print("COAP pkt recvd from "); IotsaSerial.print(ip); IotsaSerial.print(" port "); IotsaSerial.println(port);
    IotsaSerial.print("type "); IotsaSerial.println(int(pkt.type));
    IotsaSerial.print("code "); IotsaSerial.println(int(pkt.code));
    IotsaSerial.print("tokenlen "); IotsaSerial.println(int(pkt.tokenlen));
    IotsaSerial.print("payloadlen "); IotsaSerial.println(int(pkt.payloadlen));
    IotsaSerial.print("messageid "); IotsaSerial.println(int(pkt.messageid));
    IotsaSerial.print("optionnum "); IotsaSerial.println(int(pkt.optionnum));
#endif
    bool ok = false;
    String replyData;
    // Handle requests, after chaing that type (get/put/post) is supported.
    if (pkt.code == COAP_GET) {
        IFDEBUG IotsaSerial.print("COAP-GET api ");
        IFDEBUG IotsaSerial.println(path);
        ok = get;
        if (ok) {
            DynamicJsonDocument replyDocument(2048);
            JsonObject reply = replyDocument.to<JsonObject>();
            ok = provider->getHandler(path, reply);
            if (ok) {
                serializeJson(replyDocument, replyData);
            }
        }
    } else
    if (pkt.code == COAP_PUT) {
        IFDEBUG IotsaSerial.print("COAP-PUT api ");
        IFDEBUG IotsaSerial.println(path);
        ok = put;
        // xxxjack Should look through pkt.options looking for mimetype=application/json
        if (ok) {
            char dataBuffer[pkt.payloadlen+1];
            memcpy(dataBuffer, pkt.payload, pkt.payloadlen);
            dataBuffer[pkt.payloadlen] = 0;
#ifdef COAP_PROTOCOL_DEBUG
            IotsaSerial.print("payload "); IotsaSerial.println(dataBuffer);
#endif
            DynamicJsonDocument requestDocument(2048);
            deserializeJson(requestDocument, dataBuffer);
            DynamicJsonDocument replyDocument(2048);
            JsonObject request = requestDocument.as<JsonObject>();
            JsonObject reply = replyDocument.to<JsonObject>();

            ok = provider->putHandler(path, request, reply);
            if (ok) {
                serializeJson(replyDocument, replyData);
            }
        }
    } else
    if (pkt.code == COAP_POST) {
        IFDEBUG IotsaSerial.print("COAP-POST api ");
        IFDEBUG IotsaSerial.println(path);
        ok = post;
        // xxxjack Should look through pkt.options looking for mimetype=application/json
        if (ok) {
            char dataBuffer[pkt.payloadlen+1];
            memcpy(dataBuffer, pkt.payload, pkt.payloadlen);
            dataBuffer[pkt.payloadlen] = 0;
#ifdef COAP_PROTOCOL_DEBUG
            IotsaSerial.print("payload "); IotsaSerial.println(dataBuffer);
#endif
            DynamicJsonDocument requestDocument(2048);
            deserializeJson(requestDocument, dataBuffer);
            DynamicJsonDocument replyDocument(2048);
            JsonObject request = requestDocument.as<JsonObject>();
            JsonObject reply = replyDocument.to<JsonObject>();
            ok = provider->postHandler(path, request, reply);
            if (ok) {
                serializeJson(replyDocument, replyData);
            }
        }
    } else {
        IFDEBUG IotsaSerial.print("COAP-UNKNOWN ");
        IFDEBUG IotsaSerial.println(int(pkt.code));
    }
    // Send reply, either a JSON datastructure or an error.
    if (ok) {
#ifdef COAP_PROTOCOL_DEBUG
        IotsaSerial.print("replyData "); IotsaSerial.println(replyData);
        IotsaSerial.print("replyLen "); IotsaSerial.println(replyData.length());
#endif
        int rv = coap->sendResponse(ip, port, pkt.messageid, replyData.c_str(), replyData.length(), COAP_CONTENT, COAP_APPLICATION_JSON, pkt.token, pkt.tokenlen);
        if (rv) {
            IFDEBUG IotsaSerial.println("-> OK");
        } else {
            coap->sendResponse(ip, port, pkt.messageid, NULL, 0, COAP_INTERNAL_SERVER_ERROR, COAP_NONE, pkt.token, pkt.tokenlen);
            IotsaSerial.println("-> xmitReplyError");
        }
    } else {
        coap->sendResponse(ip, port, pkt.messageid, NULL, 0, COAP_BAD_REQUEST, COAP_NONE, pkt.token, pkt.tokenlen);
        IFDEBUG IotsaSerial.println("-> ERR");
    }
    delay(2000); // xxxjack
}

class IotsaCoapServiceMod : public IotsaBaseMod {
public:
  IotsaCoapServiceMod(IotsaApplication &_app);
  void setup();
  void loop();
  void addEndpoint(CoapEndpoint *ep, const char *path);
protected:
  CoapEndpoint *firstEndpoint;
  WiFiUDP udp;
  Coap coap;
};

IotsaCoapServiceMod::IotsaCoapServiceMod(IotsaApplication &_app)
  : IotsaBaseMod(_app),
    firstEndpoint(NULL),
    udp(),
    coap(udp)
  {}

void IotsaCoapServiceMod::setup() {
    if (!iotsaConfig.wifiEnabled) return;
    coap.start();
}

void IotsaCoapServiceMod::loop() {
    if (!iotsaConfig.wifiEnabled) return;
    coap.loop();
}

void IotsaCoapServiceMod::addEndpoint(CoapEndpoint *ep, const char *path) {
    if (!iotsaConfig.wifiEnabled) return;
    ep->next = firstEndpoint;
    firstEndpoint = ep;
    coap.server(ep->getCallback(&coap), String(path));
}

IotsaCoapApiService::IotsaCoapApiService(IotsaApiProvider* _provider, IotsaApplication &_app)
  : provider(_provider)
{
  if (_coapMod == NULL) _coapMod = new IotsaCoapServiceMod(_app);
}

void IotsaCoapApiService::setup(const char* path, bool get, bool put, bool post) {
    if (!iotsaConfig.wifiEnabled) return;
    CoapEndpoint *ep = new CoapEndpoint(provider, path, get, put, post);
    if (strncmp(path, "/api/", 5) == 0) path += 5;
    _coapMod->addEndpoint(ep, path);
}

#endif<|endoftext|>


<commit_before>#include "SyncOutputObject.h"

#include <maya/MFloatArray.h>
#include <maya/MGlobal.h>
#include <maya/MPlug.h>

#include <maya/MFnDependencyNode.h>
#include <maya/MFnDagNode.h>
#include <maya/MDagPath.h>

#include "AssetNode.h"
#include "SyncOutputGeometryPart.h"
#include "SyncOutputInstance.h"

#if MAYA_API_VERSION >= 201400
        #include <maya/MFnFloatArrayData.h>
#endif

SyncOutputObject::SyncOutputObject(
        const MPlug &outputPlug,
        const MObject &assetNodeObj,
        const bool visible,
        const bool syncTemplatedGeos)
    : myOutputPlug(outputPlug),
      myAssetNodeObj(assetNodeObj),
      myVisible(visible),
      mySyncTemplatedGeos(syncTemplatedGeos)
{}

SyncOutputObject::~SyncOutputObject()
{
    for(AssetSyncs::const_iterator it = myAssetSyncs.begin();
            it != myAssetSyncs.end();
            it++)
    {
        delete *it;
    }
    myAssetSyncs.clear();
}

MStatus
SyncOutputObject::doIt()
{
    MStatus status;
    // Create our parts.
    // An object just contains a number of parts, and no
    // other information.
    MFnDependencyNode assetNodeFn(myAssetNodeObj, &status);

    MObject objectTransform = myDagModifier.createNode("transform", myAssetNodeObj, &status);
    CHECK_MSTATUS_AND_RETURN_IT(status);

    // rename objectTransform
    MPlug objectNamePlug = myOutputPlug.child(AssetNode::outputObjectName);

    MString objectName = objectNamePlug.asString();
    if(objectName.length())
    {
        objectName = Util::sanitizeStringForNodeName(objectName);
    }
    else
    {
        objectName = "emptyObject";
    }
    status = myDagModifier.renameNode(objectTransform, objectName);
    CHECK_MSTATUS_AND_RETURN_IT(status);
    CHECK_MSTATUS_AND_RETURN_IT(myDagModifier.doIt());

    MFnDependencyNode objectTransformFn(objectTransform);

    // connect objectTransform attributes
    {
        MPlug transformPlug = myOutputPlug.child(AssetNode::outputObjectTransform);

        MPlug srcPlug;
        MPlug dstPlug;

        srcPlug = transformPlug.child(AssetNode::outputObjectTranslate);
        dstPlug = objectTransformFn.findPlug("translate");
        status = myDagModifier.connect(srcPlug, dstPlug);
        CHECK_MSTATUS_AND_RETURN_IT(status);

        srcPlug = transformPlug.child(AssetNode::outputObjectRotate);
        dstPlug = objectTransformFn.findPlug("rotate");
        status = myDagModifier.connect(srcPlug, dstPlug);
        CHECK_MSTATUS_AND_RETURN_IT(status);

        srcPlug = transformPlug.child(AssetNode::outputObjectScale);
        dstPlug = objectTransformFn.findPlug("scale");
        status = myDagModifier.connect(srcPlug, dstPlug);
        CHECK_MSTATUS_AND_RETURN_IT(status);

        CHECK_MSTATUS_AND_RETURN_IT(myDagModifier.doIt());
    }

    if(!myVisible)
    {
        status = myDagModifier.newPlugValueBool(
                objectTransformFn.findPlug("visibility"),
                false
                );
        CHECK_MSTATUS_AND_RETURN_IT(status);
    }

    MPlug geosPlug = myOutputPlug.child(AssetNode::outputGeos);
    int geoCount = geosPlug.evaluateNumElements(&status);
    CHECK_MSTATUS_AND_RETURN_IT(status);
    for(int ii = 0; ii < geoCount; ii++)
    {
        MPlug geoPlug = geosPlug[ii];

        MObject geoTransform = MObject::kNullObj;
        MObject partParent = objectTransform;

        MPlug isTemplatedPlug = geoPlug.child(AssetNode::outputGeoIsTemplated);
        MPlug isDisplayGeoPlug = geoPlug.child(AssetNode::outputGeoIsDisplayGeo);
        if(mySyncTemplatedGeos || !isTemplatedPlug.asBool() || isDisplayGeoPlug.asBool())
        {
            if(geoCount > 1)
            {
                geoTransform = myDagModifier.createNode("transform", objectTransform, &status);
                CHECK_MSTATUS_AND_RETURN_IT(status);

                // rename geoTransform
                MPlug geoNamePlug = geoPlug.child(AssetNode::outputGeoName);
                MString geoName = geoNamePlug.asString();
                if(geoName.length())
                {
                    geoName = Util::sanitizeStringForNodeName(geoName);
                }
                else
                {
                    geoName = "emptyGeo";
                }
                status = myDagModifier.renameNode(geoTransform, geoName);
                CHECK_MSTATUS_AND_RETURN_IT(status);
                CHECK_MSTATUS_AND_RETURN_IT(myDagModifier.doIt());

                partParent = geoTransform;
            }

            MPlug partsPlug = geoPlug.child(AssetNode::outputParts);
            int partCount = partsPlug.evaluateNumElements(&status);
            CHECK_MSTATUS_AND_RETURN_IT(status);
            for(int jj=0; jj<partCount; jj++)
            {
                SubCommand* sync = new SyncOutputGeometryPart(partsPlug[jj], partParent);
                sync->doIt();
                myAssetSyncs.push_back(sync);
            }
        }
    }

#if MAYA_API_VERSION >= 201400
    createFluidShape(objectTransform);
#endif

    return MStatus::kSuccess;
}

#if MAYA_API_VERSION >= 201400
MStatus
SyncOutputObject::createVelocityConverter(MObject& velocityConverter)
{
    if(!velocityConverter.isNull())
        return MS::kSuccess;

    MStatus status;
    velocityConverter = ((MDGModifier&)myDagModifier).createNode("houdiniFluidVelocityConvert", &status);
    CHECK_MSTATUS_AND_RETURN_IT(status);
    return status;
}

bool
SyncOutputObject::resolutionsEqual(MPlug resA, MPlug resB)
{
    MPlug resAPlug = resA.child(AssetNode::outputPartVolumeRes);
    MObject resAObj;
    resAPlug.getValue(resAObj);

    MPlug resBPlug = resB.child(AssetNode::outputPartVolumeRes);
    MObject resBObj;
    resBPlug.getValue(resBObj);

    MStatus status;
    MFnFloatArrayData dataA(resAObj, &status);
    MFnFloatArrayData dataB(resBObj, &status);

    return dataA[0] == dataB[0] &&
           dataA[1] == dataB[1] &&
           dataA[2] == dataB[2];
}

MStatus
SyncOutputObject::createFluidShape(const MObject &objectTransform)
{
    MStatus status;

    MPlug geosPlug = myOutputPlug.child(AssetNode::outputGeos);
    int geoCount = geosPlug.evaluateNumElements(&status);
    CHECK_MSTATUS_AND_RETURN_IT(status);
    for(int ii = 0; ii < geoCount; ii++)
    {
        MPlug geoPlug = geosPlug[ii];

        MPlug partsPlug = geoPlug.child(AssetNode::outputParts);
        int partCount = partsPlug.evaluateNumElements(&status);
        CHECK_MSTATUS_AND_RETURN_IT(status);

        // Look for specific volume names. Once we've found the first reference
        // volume, look again through everything for any volumes which share a
        // transform with the first reference volume, and add them to the
        // fluidShape.
        bool hasFluid = false;
        MPlug referenceVolume;
        for(int jj=0; jj<partCount; jj++)
        {
            MPlug outputVolume = partsPlug[jj].child(AssetNode::outputPartVolume);
            MPlug outputPartName = partsPlug[jj].child(AssetNode::outputPartName);
            MPlug outputVolumeName = outputVolume.child(AssetNode::outputPartVolumeName);

            MString name = outputVolumeName.asString();

            if(name == "density"
                    || name == "temperature"
                    || name == "fuel"
                    || name == "vel.x"
                    || name == "vel.y"
                    || name == "vel.z")
            {
                hasFluid = true;
                referenceVolume = outputVolume;
                break;
            }
        }

        if(!hasFluid)
            return MStatus::kSuccess;

        MObject transform, fluid;
        {
            transform = myDagModifier.createNode("transform", objectTransform, &status);
            CHECK_MSTATUS_AND_RETURN_IT(status);
            // TODO: name
            status  = myDagModifier.renameNode(transform, "fluid_transform");
            CHECK_MSTATUS_AND_RETURN_IT(status);

            fluid = myDagModifier.createNode("fluidShape", transform, &status);
            CHECK_MSTATUS_AND_RETURN_IT(status);
        }

        MPlug referenceRes = referenceVolume.child(AssetNode::outputPartVolumeRes);

        MFnDagNode partVolumeFn(fluid, &status);
        CHECK_MSTATUS_AND_RETURN_IT(status);
        MFnDagNode partFluidTransformFn(transform, &status);
        CHECK_MSTATUS_AND_RETURN_IT(status);

        MObject velConverter;

        bool doneDensity = false;
        bool doneTemperature = false;
        bool doneFuel = false;
        bool doneVelX = false;
        bool doneVelY = false;
        bool doneVelZ = false;
        for(int jj=0; jj<partCount; jj++)
        {
            MPlug outputVolume = partsPlug[jj].child(AssetNode::outputPartVolume);
            MPlug outputVolumeName = outputVolume.child(AssetNode::outputPartVolumeName);
            MPlug outputVolumeRes= outputVolume.child(AssetNode::outputPartVolumeRes);

            // If the transform of the volumes are different, we don't want
            // to group them together.
            if(!resolutionsEqual(outputVolumeRes, referenceRes))
                continue;

            MPlug srcPlug = outputVolume.child(AssetNode::outputPartVolumeGrid);
            MString name = outputVolumeName.asString();
            if(name == "density" && !doneDensity)
            {
                status = myDagModifier.connect(srcPlug, partVolumeFn.findPlug("inDensity"));
                CHECK_MSTATUS_AND_RETURN_IT(status);
                status = myDagModifier.newPlugValueInt(
                        partVolumeFn.findPlug("densityMethod"),
                        2
                        );
                CHECK_MSTATUS_AND_RETURN_IT(status);
                doneDensity = true;
            }
            else if(name == "temperature" && !doneTemperature)
            {
                status = myDagModifier.connect(srcPlug, partVolumeFn.findPlug("inTemperature"));
                CHECK_MSTATUS_AND_RETURN_IT(status);
                status = myDagModifier.newPlugValueInt(
                        partVolumeFn.findPlug("temperatureMethod"),
                        2
                        );
                CHECK_MSTATUS_AND_RETURN_IT(status);
                doneTemperature = true;
            }
            else if(name == "fuel" && !doneFuel)
            {
                status = myDagModifier.connect(srcPlug, partVolumeFn.findPlug("inReaction"));
                CHECK_MSTATUS_AND_RETURN_IT(status);
                status = myDagModifier.newPlugValueInt(
                        partVolumeFn.findPlug("fuelMethod"),
                        2
                        );
                CHECK_MSTATUS_AND_RETURN_IT(status);
                doneFuel = true;
            }
            else if(name == "vel.x" && !doneVelX)
            {
                createVelocityConverter(velConverter);
                MFnDependencyNode velConverterFn(velConverter, &status);
                CHECK_MSTATUS_AND_RETURN_IT(status);
                status = myDagModifier.connect(srcPlug, velConverterFn.findPlug("inGridX"));
                CHECK_MSTATUS_AND_RETURN_IT(status);
                doneVelX = true;
            }
            else if(name == "vel.y" && !doneVelY)
            {
                createVelocityConverter(velConverter);
                MFnDependencyNode velConverterFn(velConverter, &status);
                CHECK_MSTATUS_AND_RETURN_IT(status);
                status = myDagModifier.connect(srcPlug, velConverterFn.findPlug("inGridY"));
                CHECK_MSTATUS_AND_RETURN_IT(status);
                doneVelY = true;
            }
            else if(name == "vel.z" && !doneVelZ)
            {
                createVelocityConverter(velConverter);
                MFnDependencyNode velConverterFn(velConverter, &status);
                CHECK_MSTATUS_AND_RETURN_IT(status);
                status = myDagModifier.connect(srcPlug, velConverterFn.findPlug("inGridZ"));
                CHECK_MSTATUS_AND_RETURN_IT(status);
                doneVelZ = true;
            }
        }

        // Connect the transform, resolution, playFromCache; set inOffset and dimensions
        {
            MPlug srcPlug;
            MPlug dstPlug;

            MPlug densityTransform = referenceVolume.child(AssetNode::outputPartVolumeTransform);

            srcPlug = densityTransform.child(AssetNode::outputPartVolumeTranslate);
            dstPlug = partFluidTransformFn.findPlug("translate");
            status = myDagModifier.connect(srcPlug, dstPlug);
            CHECK_MSTATUS_AND_RETURN_IT(status);

            srcPlug = referenceVolume.child(AssetNode::outputPartVolumeRes);
            dstPlug = partVolumeFn.findPlug("inResolution");
            status = myDagModifier.connect(srcPlug, dstPlug);
            CHECK_MSTATUS_AND_RETURN_IT(status);

            srcPlug = densityTransform.child(AssetNode::outputPartVolumeRotate);
            dstPlug = partFluidTransformFn.findPlug("rotate");
            status = myDagModifier.connect(srcPlug, dstPlug);
            CHECK_MSTATUS_AND_RETURN_IT(status);

            srcPlug = densityTransform.child(AssetNode::outputPartVolumeScale);
            dstPlug = partFluidTransformFn.findPlug("scale");
            status = myDagModifier.connect(srcPlug, dstPlug);
            CHECK_MSTATUS_AND_RETURN_IT(status);

            // Velocity needs an additional step: since houdini may output
            // individual grids for each component, we use a dependency node
            // to append and extrapolate the components
            if(!velConverter.isNull())
            {
                MFnDependencyNode velConverterFn(velConverter, &status);

                srcPlug = referenceVolume.child(AssetNode::outputPartVolumeRes);
                dstPlug = velConverterFn.findPlug("resolution");
                status = myDagModifier.connect(srcPlug, dstPlug);
                CHECK_MSTATUS_AND_RETURN_IT(status);

                srcPlug = velConverterFn.findPlug("outGrid");
                dstPlug = partVolumeFn.findPlug("inVelocity");
                status = myDagModifier.connect(srcPlug, dstPlug);
                CHECK_MSTATUS_AND_RETURN_IT(status);
            }

            // time1.outTime -> fluidShape.currentTime
            {
                MObject srcNode = Util::findNodeByName("time1");
                srcPlug = MFnDependencyNode(srcNode).findPlug("outTime");
                dstPlug = partVolumeFn.findPlug("currentTime");
                status = myDagModifier.connect(srcPlug, dstPlug);
                CHECK_MSTATUS_AND_RETURN_IT(status);
            }

            srcPlug = myOutputPlug.child(AssetNode::outputObjectFluidFromAsset);
            dstPlug = partVolumeFn.findPlug("playFromCache");
            status = myDagModifier.connect(srcPlug, dstPlug);
            CHECK_MSTATUS_AND_RETURN_IT(status);

            // inOffset must be initialized or bugs will be had; and the math is
            // simpler with dimensions all equal to 1.
            MFloatArray offset;
            offset.append(0);
            offset.append(0);
            offset.append(0);
            MFnFloatArrayData offsetCreator;
            MObject data = offsetCreator.create(offset);
            partVolumeFn.findPlug("inOffset").setValue(data);
            partVolumeFn.findPlug("dimensionsW").setValue(1);
            partVolumeFn.findPlug("dimensionsH").setValue(1);
            partVolumeFn.findPlug("dimensionsD").setValue(1);
        }

        // doIt so that we can access the fullPathName
        status = myDagModifier.doIt();
        CHECK_MSTATUS_AND_RETURN_IT(status);

        // assign shader
        status = myDagModifier.commandToExecute(
                "assignSG " + partVolumeFn.fullPathName() + " " + partVolumeFn.fullPathName()
                );
        CHECK_MSTATUS_AND_RETURN_IT(status);
    }

    status = myDagModifier.doIt();
    CHECK_MSTATUS_AND_RETURN_IT(status);

    return MStatus::kSuccess;
}
#endif

MStatus
SyncOutputObject::undoIt()
{
    for(AssetSyncs::reverse_iterator iter = myAssetSyncs.rbegin();
            iter != myAssetSyncs.rend();
            iter++)
    {
        (*iter)->undoIt();
    }
    myDagModifier.undoIt();

    return MStatus::kSuccess;
}

MStatus
SyncOutputObject::redoIt()
{
    myDagModifier.doIt();
    for(AssetSyncs::iterator iter = myAssetSyncs.begin();
            iter != myAssetSyncs.end();
            iter++)
    {
        (*iter)->redoIt();
    }

    return MStatus::kSuccess;
}

bool
SyncOutputObject::isUndoable() const
{
    return true;
}
<commit_msg>Change the fluid transform's name to "fluid"<commit_after>#include "SyncOutputObject.h"

#include <maya/MFloatArray.h>
#include <maya/MGlobal.h>
#include <maya/MPlug.h>

#include <maya/MFnDependencyNode.h>
#include <maya/MFnDagNode.h>
#include <maya/MDagPath.h>

#include "AssetNode.h"
#include "SyncOutputGeometryPart.h"
#include "SyncOutputInstance.h"

#if MAYA_API_VERSION >= 201400
        #include <maya/MFnFloatArrayData.h>
#endif

SyncOutputObject::SyncOutputObject(
        const MPlug &outputPlug,
        const MObject &assetNodeObj,
        const bool visible,
        const bool syncTemplatedGeos)
    : myOutputPlug(outputPlug),
      myAssetNodeObj(assetNodeObj),
      myVisible(visible),
      mySyncTemplatedGeos(syncTemplatedGeos)
{}

SyncOutputObject::~SyncOutputObject()
{
    for(AssetSyncs::const_iterator it = myAssetSyncs.begin();
            it != myAssetSyncs.end();
            it++)
    {
        delete *it;
    }
    myAssetSyncs.clear();
}

MStatus
SyncOutputObject::doIt()
{
    MStatus status;
    // Create our parts.
    // An object just contains a number of parts, and no
    // other information.
    MFnDependencyNode assetNodeFn(myAssetNodeObj, &status);

    MObject objectTransform = myDagModifier.createNode("transform", myAssetNodeObj, &status);
    CHECK_MSTATUS_AND_RETURN_IT(status);

    // rename objectTransform
    MPlug objectNamePlug = myOutputPlug.child(AssetNode::outputObjectName);

    MString objectName = objectNamePlug.asString();
    if(objectName.length())
    {
        objectName = Util::sanitizeStringForNodeName(objectName);
    }
    else
    {
        objectName = "emptyObject";
    }
    status = myDagModifier.renameNode(objectTransform, objectName);
    CHECK_MSTATUS_AND_RETURN_IT(status);
    CHECK_MSTATUS_AND_RETURN_IT(myDagModifier.doIt());

    MFnDependencyNode objectTransformFn(objectTransform);

    // connect objectTransform attributes
    {
        MPlug transformPlug = myOutputPlug.child(AssetNode::outputObjectTransform);

        MPlug srcPlug;
        MPlug dstPlug;

        srcPlug = transformPlug.child(AssetNode::outputObjectTranslate);
        dstPlug = objectTransformFn.findPlug("translate");
        status = myDagModifier.connect(srcPlug, dstPlug);
        CHECK_MSTATUS_AND_RETURN_IT(status);

        srcPlug = transformPlug.child(AssetNode::outputObjectRotate);
        dstPlug = objectTransformFn.findPlug("rotate");
        status = myDagModifier.connect(srcPlug, dstPlug);
        CHECK_MSTATUS_AND_RETURN_IT(status);

        srcPlug = transformPlug.child(AssetNode::outputObjectScale);
        dstPlug = objectTransformFn.findPlug("scale");
        status = myDagModifier.connect(srcPlug, dstPlug);
        CHECK_MSTATUS_AND_RETURN_IT(status);

        CHECK_MSTATUS_AND_RETURN_IT(myDagModifier.doIt());
    }

    if(!myVisible)
    {
        status = myDagModifier.newPlugValueBool(
                objectTransformFn.findPlug("visibility"),
                false
                );
        CHECK_MSTATUS_AND_RETURN_IT(status);
    }

    MPlug geosPlug = myOutputPlug.child(AssetNode::outputGeos);
    int geoCount = geosPlug.evaluateNumElements(&status);
    CHECK_MSTATUS_AND_RETURN_IT(status);
    for(int ii = 0; ii < geoCount; ii++)
    {
        MPlug geoPlug = geosPlug[ii];

        MObject geoTransform = MObject::kNullObj;
        MObject partParent = objectTransform;

        MPlug isTemplatedPlug = geoPlug.child(AssetNode::outputGeoIsTemplated);
        MPlug isDisplayGeoPlug = geoPlug.child(AssetNode::outputGeoIsDisplayGeo);
        if(mySyncTemplatedGeos || !isTemplatedPlug.asBool() || isDisplayGeoPlug.asBool())
        {
            if(geoCount > 1)
            {
                geoTransform = myDagModifier.createNode("transform", objectTransform, &status);
                CHECK_MSTATUS_AND_RETURN_IT(status);

                // rename geoTransform
                MPlug geoNamePlug = geoPlug.child(AssetNode::outputGeoName);
                MString geoName = geoNamePlug.asString();
                if(geoName.length())
                {
                    geoName = Util::sanitizeStringForNodeName(geoName);
                }
                else
                {
                    geoName = "emptyGeo";
                }
                status = myDagModifier.renameNode(geoTransform, geoName);
                CHECK_MSTATUS_AND_RETURN_IT(status);
                CHECK_MSTATUS_AND_RETURN_IT(myDagModifier.doIt());

                partParent = geoTransform;
            }

            MPlug partsPlug = geoPlug.child(AssetNode::outputParts);
            int partCount = partsPlug.evaluateNumElements(&status);
            CHECK_MSTATUS_AND_RETURN_IT(status);
            for(int jj=0; jj<partCount; jj++)
            {
                SubCommand* sync = new SyncOutputGeometryPart(partsPlug[jj], partParent);
                sync->doIt();
                myAssetSyncs.push_back(sync);
            }
        }
    }

#if MAYA_API_VERSION >= 201400
    createFluidShape(objectTransform);
#endif

    return MStatus::kSuccess;
}

#if MAYA_API_VERSION >= 201400
MStatus
SyncOutputObject::createVelocityConverter(MObject& velocityConverter)
{
    if(!velocityConverter.isNull())
        return MS::kSuccess;

    MStatus status;
    velocityConverter = ((MDGModifier&)myDagModifier).createNode("houdiniFluidVelocityConvert", &status);
    CHECK_MSTATUS_AND_RETURN_IT(status);
    return status;
}

bool
SyncOutputObject::resolutionsEqual(MPlug resA, MPlug resB)
{
    MPlug resAPlug = resA.child(AssetNode::outputPartVolumeRes);
    MObject resAObj;
    resAPlug.getValue(resAObj);

    MPlug resBPlug = resB.child(AssetNode::outputPartVolumeRes);
    MObject resBObj;
    resBPlug.getValue(resBObj);

    MStatus status;
    MFnFloatArrayData dataA(resAObj, &status);
    MFnFloatArrayData dataB(resBObj, &status);

    return dataA[0] == dataB[0] &&
           dataA[1] == dataB[1] &&
           dataA[2] == dataB[2];
}

MStatus
SyncOutputObject::createFluidShape(const MObject &objectTransform)
{
    MStatus status;

    MPlug geosPlug = myOutputPlug.child(AssetNode::outputGeos);
    int geoCount = geosPlug.evaluateNumElements(&status);
    CHECK_MSTATUS_AND_RETURN_IT(status);
    for(int ii = 0; ii < geoCount; ii++)
    {
        MPlug geoPlug = geosPlug[ii];

        MPlug partsPlug = geoPlug.child(AssetNode::outputParts);
        int partCount = partsPlug.evaluateNumElements(&status);
        CHECK_MSTATUS_AND_RETURN_IT(status);

        // Look for specific volume names. Once we've found the first reference
        // volume, look again through everything for any volumes which share a
        // transform with the first reference volume, and add them to the
        // fluidShape.
        bool hasFluid = false;
        MPlug referenceVolume;
        for(int jj=0; jj<partCount; jj++)
        {
            MPlug outputVolume = partsPlug[jj].child(AssetNode::outputPartVolume);
            MPlug outputPartName = partsPlug[jj].child(AssetNode::outputPartName);
            MPlug outputVolumeName = outputVolume.child(AssetNode::outputPartVolumeName);

            MString name = outputVolumeName.asString();

            if(name == "density"
                    || name == "temperature"
                    || name == "fuel"
                    || name == "vel.x"
                    || name == "vel.y"
                    || name == "vel.z")
            {
                hasFluid = true;
                referenceVolume = outputVolume;
                break;
            }
        }

        if(!hasFluid)
            return MStatus::kSuccess;

        MObject transform, fluid;
        {
            transform = myDagModifier.createNode("transform", objectTransform, &status);
            CHECK_MSTATUS_AND_RETURN_IT(status);
            // TODO: name
            status  = myDagModifier.renameNode(transform, "fluid");
            CHECK_MSTATUS_AND_RETURN_IT(status);

            fluid = myDagModifier.createNode("fluidShape", transform, &status);
            CHECK_MSTATUS_AND_RETURN_IT(status);
        }

        MPlug referenceRes = referenceVolume.child(AssetNode::outputPartVolumeRes);

        MFnDagNode partVolumeFn(fluid, &status);
        CHECK_MSTATUS_AND_RETURN_IT(status);
        MFnDagNode partFluidTransformFn(transform, &status);
        CHECK_MSTATUS_AND_RETURN_IT(status);

        MObject velConverter;

        bool doneDensity = false;
        bool doneTemperature = false;
        bool doneFuel = false;
        bool doneVelX = false;
        bool doneVelY = false;
        bool doneVelZ = false;
        for(int jj=0; jj<partCount; jj++)
        {
            MPlug outputVolume = partsPlug[jj].child(AssetNode::outputPartVolume);
            MPlug outputVolumeName = outputVolume.child(AssetNode::outputPartVolumeName);
            MPlug outputVolumeRes= outputVolume.child(AssetNode::outputPartVolumeRes);

            // If the transform of the volumes are different, we don't want
            // to group them together.
            if(!resolutionsEqual(outputVolumeRes, referenceRes))
                continue;

            MPlug srcPlug = outputVolume.child(AssetNode::outputPartVolumeGrid);
            MString name = outputVolumeName.asString();
            if(name == "density" && !doneDensity)
            {
                status = myDagModifier.connect(srcPlug, partVolumeFn.findPlug("inDensity"));
                CHECK_MSTATUS_AND_RETURN_IT(status);
                status = myDagModifier.newPlugValueInt(
                        partVolumeFn.findPlug("densityMethod"),
                        2
                        );
                CHECK_MSTATUS_AND_RETURN_IT(status);
                doneDensity = true;
            }
            else if(name == "temperature" && !doneTemperature)
            {
                status = myDagModifier.connect(srcPlug, partVolumeFn.findPlug("inTemperature"));
                CHECK_MSTATUS_AND_RETURN_IT(status);
                status = myDagModifier.newPlugValueInt(
                        partVolumeFn.findPlug("temperatureMethod"),
                        2
                        );
                CHECK_MSTATUS_AND_RETURN_IT(status);
                doneTemperature = true;
            }
            else if(name == "fuel" && !doneFuel)
            {
                status = myDagModifier.connect(srcPlug, partVolumeFn.findPlug("inReaction"));
                CHECK_MSTATUS_AND_RETURN_IT(status);
                status = myDagModifier.newPlugValueInt(
                        partVolumeFn.findPlug("fuelMethod"),
                        2
                        );
                CHECK_MSTATUS_AND_RETURN_IT(status);
                doneFuel = true;
            }
            else if(name == "vel.x" && !doneVelX)
            {
                createVelocityConverter(velConverter);
                MFnDependencyNode velConverterFn(velConverter, &status);
                CHECK_MSTATUS_AND_RETURN_IT(status);
                status = myDagModifier.connect(srcPlug, velConverterFn.findPlug("inGridX"));
                CHECK_MSTATUS_AND_RETURN_IT(status);
                doneVelX = true;
            }
            else if(name == "vel.y" && !doneVelY)
            {
                createVelocityConverter(velConverter);
                MFnDependencyNode velConverterFn(velConverter, &status);
                CHECK_MSTATUS_AND_RETURN_IT(status);
                status = myDagModifier.connect(srcPlug, velConverterFn.findPlug("inGridY"));
                CHECK_MSTATUS_AND_RETURN_IT(status);
                doneVelY = true;
            }
            else if(name == "vel.z" && !doneVelZ)
            {
                createVelocityConverter(velConverter);
                MFnDependencyNode velConverterFn(velConverter, &status);
                CHECK_MSTATUS_AND_RETURN_IT(status);
                status = myDagModifier.connect(srcPlug, velConverterFn.findPlug("inGridZ"));
                CHECK_MSTATUS_AND_RETURN_IT(status);
                doneVelZ = true;
            }
        }

        // Connect the transform, resolution, playFromCache; set inOffset and dimensions
        {
            MPlug srcPlug;
            MPlug dstPlug;

            MPlug densityTransform = referenceVolume.child(AssetNode::outputPartVolumeTransform);

            srcPlug = densityTransform.child(AssetNode::outputPartVolumeTranslate);
            dstPlug = partFluidTransformFn.findPlug("translate");
            status = myDagModifier.connect(srcPlug, dstPlug);
            CHECK_MSTATUS_AND_RETURN_IT(status);

            srcPlug = referenceVolume.child(AssetNode::outputPartVolumeRes);
            dstPlug = partVolumeFn.findPlug("inResolution");
            status = myDagModifier.connect(srcPlug, dstPlug);
            CHECK_MSTATUS_AND_RETURN_IT(status);

            srcPlug = densityTransform.child(AssetNode::outputPartVolumeRotate);
            dstPlug = partFluidTransformFn.findPlug("rotate");
            status = myDagModifier.connect(srcPlug, dstPlug);
            CHECK_MSTATUS_AND_RETURN_IT(status);

            srcPlug = densityTransform.child(AssetNode::outputPartVolumeScale);
            dstPlug = partFluidTransformFn.findPlug("scale");
            status = myDagModifier.connect(srcPlug, dstPlug);
            CHECK_MSTATUS_AND_RETURN_IT(status);

            // Velocity needs an additional step: since houdini may output
            // individual grids for each component, we use a dependency node
            // to append and extrapolate the components
            if(!velConverter.isNull())
            {
                MFnDependencyNode velConverterFn(velConverter, &status);

                srcPlug = referenceVolume.child(AssetNode::outputPartVolumeRes);
                dstPlug = velConverterFn.findPlug("resolution");
                status = myDagModifier.connect(srcPlug, dstPlug);
                CHECK_MSTATUS_AND_RETURN_IT(status);

                srcPlug = velConverterFn.findPlug("outGrid");
                dstPlug = partVolumeFn.findPlug("inVelocity");
                status = myDagModifier.connect(srcPlug, dstPlug);
                CHECK_MSTATUS_AND_RETURN_IT(status);
            }

            // time1.outTime -> fluidShape.currentTime
            {
                MObject srcNode = Util::findNodeByName("time1");
                srcPlug = MFnDependencyNode(srcNode).findPlug("outTime");
                dstPlug = partVolumeFn.findPlug("currentTime");
                status = myDagModifier.connect(srcPlug, dstPlug);
                CHECK_MSTATUS_AND_RETURN_IT(status);
            }

            srcPlug = myOutputPlug.child(AssetNode::outputObjectFluidFromAsset);
            dstPlug = partVolumeFn.findPlug("playFromCache");
            status = myDagModifier.connect(srcPlug, dstPlug);
            CHECK_MSTATUS_AND_RETURN_IT(status);

            // inOffset must be initialized or bugs will be had; and the math is
            // simpler with dimensions all equal to 1.
            MFloatArray offset;
            offset.append(0);
            offset.append(0);
            offset.append(0);
            MFnFloatArrayData offsetCreator;
            MObject data = offsetCreator.create(offset);
            partVolumeFn.findPlug("inOffset").setValue(data);
            partVolumeFn.findPlug("dimensionsW").setValue(1);
            partVolumeFn.findPlug("dimensionsH").setValue(1);
            partVolumeFn.findPlug("dimensionsD").setValue(1);
        }

        // doIt so that we can access the fullPathName
        status = myDagModifier.doIt();
        CHECK_MSTATUS_AND_RETURN_IT(status);

        // assign shader
        status = myDagModifier.commandToExecute(
                "assignSG " + partVolumeFn.fullPathName() + " " + partVolumeFn.fullPathName()
                );
        CHECK_MSTATUS_AND_RETURN_IT(status);
    }

    status = myDagModifier.doIt();
    CHECK_MSTATUS_AND_RETURN_IT(status);

    return MStatus::kSuccess;
}
#endif

MStatus
SyncOutputObject::undoIt()
{
    for(AssetSyncs::reverse_iterator iter = myAssetSyncs.rbegin();
            iter != myAssetSyncs.rend();
            iter++)
    {
        (*iter)->undoIt();
    }
    myDagModifier.undoIt();

    return MStatus::kSuccess;
}

MStatus
SyncOutputObject::redoIt()
{
    myDagModifier.doIt();
    for(AssetSyncs::iterator iter = myAssetSyncs.begin();
            iter != myAssetSyncs.end();
            iter++)
    {
        (*iter)->redoIt();
    }

    return MStatus::kSuccess;
}

bool
SyncOutputObject::isUndoable() const
{
    return true;
}
<|endoftext|>


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

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_xmloff.hxx"

#include "XMLTextMarkImportContext.hxx"

#ifndef _RTL_USTRING
#include <rtl/ustring.hxx>
#endif

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

#ifndef _XMLOFF_XMLUCONV_HXX
#include <xmloff/xmluconv.hxx>
#endif

#ifndef _XMLOFF_XMLTOKEN_HXX
#include <xmloff/xmltoken.hxx>
#endif

#ifndef _XMLOFF_XMLIMP_HXX
#include <xmloff/xmlimp.hxx>
#endif

#ifndef _XMLOFF_NMSPMAP_HXX
#include <xmloff/nmspmap.hxx>
#endif

#ifndef _XMLOFF_XMLNMSPE_HXX
#include "xmlnmspe.hxx"
#endif

#ifndef _COM_SUN_STAR_XML_SAX_XATTRIBUTELIST_HPP_
#include <com/sun/star/xml/sax/XAttributeList.hpp>
#endif

#ifndef _COM_SUN_STAR_TEXT_XTEXTCONTENT_HPP_
#include <com/sun/star/text/XTextContent.hpp>
#endif

#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
#include <com/sun/star/beans/XPropertySet.hpp>
#endif

#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif

#ifndef _COM_SUN_STAR_CONTAINER_XNAMED_HPP_
#include <com/sun/star/container/XNamed.hpp>
#endif

using ::rtl::OUString;
using ::rtl::OUStringBuffer;

using namespace ::com::sun::star::text;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::xml::sax;
using namespace ::xmloff::token;

TYPEINIT1( XMLTextMarkImportContext, SvXMLImportContext);

XMLTextMarkImportContext::XMLTextMarkImportContext(
    SvXMLImport& rImport,
    XMLTextImportHelper& rHlp,
    sal_uInt16 nPrefix,
    const OUString& rLocalName ) :
        SvXMLImportContext(rImport, nPrefix, rLocalName),
        rHelper(rHlp)
{
}

enum lcl_MarkType { TypeReference, TypeReferenceStart, TypeReferenceEnd,
                    TypeBookmark, TypeBookmarkStart, TypeBookmarkEnd };

static SvXMLEnumMapEntry __READONLY_DATA lcl_aMarkTypeMap[] =
{
    { XML_REFERENCE_MARK,           TypeReference },
    { XML_REFERENCE_MARK_START,     TypeReferenceStart },
    { XML_REFERENCE_MARK_END,       TypeReferenceEnd },
    { XML_BOOKMARK,                 TypeBookmark },
    { XML_BOOKMARK_START,           TypeBookmarkStart },
    { XML_BOOKMARK_END,             TypeBookmarkEnd },
    { XML_TOKEN_INVALID,            0 },
};

void XMLTextMarkImportContext::StartElement(
    const Reference<XAttributeList> & xAttrList)
{
    const OUString sAPI_reference_mark(
        RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.ReferenceMark"));
    const OUString sAPI_bookmark(
        RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.Bookmark"));

    OUString sName;

    if (FindName(GetImport(), xAttrList, sName))
    {
        sal_uInt16 nTmp;
        if (SvXMLUnitConverter::convertEnum(nTmp, GetLocalName(),
                                            lcl_aMarkTypeMap))
        {
            switch ((lcl_MarkType)nTmp)
            {
                case TypeReference:
                    // export point reference mark
                    CreateAndInsertMark(GetImport(),
                                        sAPI_reference_mark,
                                        sName,
                                       rHelper.GetCursorAsRange()->getStart());
                    break;

                case TypeBookmark:
                    // export point bookmark
                    CreateAndInsertMark(GetImport(),
                                        sAPI_bookmark,
                                        sName,
                                       rHelper.GetCursorAsRange()->getStart());
                    break;

                case TypeBookmarkStart:
                    // save XTextRange for later construction of bookmark
                    rHelper.InsertBookmarkStartRange(
                        sName, rHelper.GetCursorAsRange()->getStart());
                    break;

                case TypeBookmarkEnd:
                {
                    // get old range, and construct
                    Reference<XTextRange> xStartRange;
                    if (rHelper.FindAndRemoveBookmarkStartRange(xStartRange,
                                                                sName))
                    {
                        Reference<XTextRange> xEndRange(
                            rHelper.GetCursorAsRange()->getStart());

                        // check if beginning and end are in same XText
                        if (xStartRange->getText() == xEndRange->getText())
                        {
                            // create range for insertion
                            Reference<XTextCursor> xInsertionCursor =
                                rHelper.GetText()->createTextCursorByRange(
                                    xEndRange);
                            xInsertionCursor->gotoRange(xStartRange, sal_True);

                            //DBG_ASSERT(! xInsertionCursor->isCollapsed(),
                            //              "we want no point mark");
                            // can't assert, because someone could
                            // create a file with subsequence
                            // start/end elements

                            Reference<XTextRange> xInsertionRange(
                                xInsertionCursor, UNO_QUERY);

                            // insert reference
                            CreateAndInsertMark(GetImport(),
                                                sAPI_bookmark,
                                                sName,
                                                xInsertionRange);
                        }
                        // else: beginning/end in different XText -> ignore!
                    }
                    // else: no start found -> ignore!
                    break;
                }

                case TypeReferenceStart:
                case TypeReferenceEnd:
                    DBG_ERROR("reference start/end are handled in txtparai !");
                    break;

                default:
                    DBG_ERROR("unknown mark type");
                    break;
            }
        }
    }
}

void XMLTextMarkImportContext::CreateAndInsertMark(
    SvXMLImport& rImport,
    const OUString& sServiceName,
    const OUString& sMarkName,
    const Reference<XTextRange> & rRange)
{
    // create mark
    Reference<XMultiServiceFactory> xFactory(rImport.GetModel(),UNO_QUERY);
    if( xFactory.is() )
    {
        Reference<XInterface> xIfc = xFactory->createInstance(sServiceName);

        // set name
        Reference<XNamed> xNamed(xIfc, UNO_QUERY);
        if (xNamed.is())
        {
            xNamed->setName(sMarkName);

            // cast to XTextContent and attach to document
            Reference<XTextContent> xTextContent(xIfc, UNO_QUERY);
            if (xTextContent.is())
            {
                try
                {
                // if inserting marks, bAbsorb==sal_False will cause
                // collapsing of the given XTextRange.
                    rImport.GetTextImport()->GetText()->insertTextContent(rRange,
                        xTextContent, sal_True);
                }
                catch (com::sun::star::lang::IllegalArgumentException e)
                {
                    // ignore
                }
            }
        }
    }
}

sal_Bool XMLTextMarkImportContext::FindName(
    SvXMLImport& rImport,
    const Reference<XAttributeList> & xAttrList,
    OUString& sName)
{
    sal_Bool bNameOK = sal_False;

    // find name attribute first
    sal_Int16 nLength = xAttrList->getLength();
    for(sal_Int16 nAttr = 0; nAttr < nLength; nAttr++)
    {
        OUString sLocalName;
        sal_uInt16 nPrefix = rImport.GetNamespaceMap().
            GetKeyByAttrName( xAttrList->getNameByIndex(nAttr),
                              &sLocalName );

        if ( (XML_NAMESPACE_TEXT == nPrefix) &&
             IsXMLToken(sLocalName, XML_NAME)   )
        {
            sName = xAttrList->getValueByIndex(nAttr);
            bNameOK = sal_True;
        }
    }

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

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_xmloff.hxx"

#include "XMLTextMarkImportContext.hxx"

#ifndef _RTL_USTRING
#include <rtl/ustring.hxx>
#endif
#include <tools/debug.hxx>
#include <xmloff/xmluconv.hxx>
#include <xmloff/xmltoken.hxx>
#include <xmloff/xmlimp.hxx>
#include <xmloff/nmspmap.hxx>
#include "xmlnmspe.hxx"
#include <com/sun/star/xml/sax/XAttributeList.hpp>
#include <com/sun/star/text/XTextContent.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/container/XNamed.hpp>

using ::rtl::OUString;
using ::rtl::OUStringBuffer;

using namespace ::com::sun::star::text;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::xml::sax;
using namespace ::xmloff::token;

TYPEINIT1( XMLTextMarkImportContext, SvXMLImportContext);

XMLTextMarkImportContext::XMLTextMarkImportContext(
    SvXMLImport& rImport,
    XMLTextImportHelper& rHlp,
    sal_uInt16 nPrefix,
    const OUString& rLocalName ) :
        SvXMLImportContext(rImport, nPrefix, rLocalName),
        rHelper(rHlp)
{
}

enum lcl_MarkType { TypeReference, TypeReferenceStart, TypeReferenceEnd,
                    TypeBookmark, TypeBookmarkStart, TypeBookmarkEnd };

static SvXMLEnumMapEntry __READONLY_DATA lcl_aMarkTypeMap[] =
{
    { XML_REFERENCE_MARK,           TypeReference },
    { XML_REFERENCE_MARK_START,     TypeReferenceStart },
    { XML_REFERENCE_MARK_END,       TypeReferenceEnd },
    { XML_BOOKMARK,                 TypeBookmark },
    { XML_BOOKMARK_START,           TypeBookmarkStart },
    { XML_BOOKMARK_END,             TypeBookmarkEnd },
    { XML_TOKEN_INVALID,            0 },
};

void XMLTextMarkImportContext::StartElement(
    const Reference<XAttributeList> & xAttrList)
{
    const OUString sAPI_reference_mark(
        RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.ReferenceMark"));
    const OUString sAPI_bookmark(
        RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.Bookmark"));

    OUString sName;

    if (FindName(GetImport(), xAttrList, sName))
    {
        sal_uInt16 nTmp;
        if (SvXMLUnitConverter::convertEnum(nTmp, GetLocalName(),
                                            lcl_aMarkTypeMap))
        {
            switch ((lcl_MarkType)nTmp)
            {
                case TypeReference:
                    // export point reference mark
                    CreateAndInsertMark(GetImport(),
                                        sAPI_reference_mark,
                                        sName,
                                       rHelper.GetCursorAsRange()->getStart());
                    break;

                case TypeBookmark:
                    // export point bookmark
                    CreateAndInsertMark(GetImport(),
                                        sAPI_bookmark,
                                        sName,
                                       rHelper.GetCursorAsRange()->getStart());
                    break;

                case TypeBookmarkStart:
                    // save XTextRange for later construction of bookmark
                    rHelper.InsertBookmarkStartRange(
                        sName, rHelper.GetCursorAsRange()->getStart());
                    break;

                case TypeBookmarkEnd:
                {
                    // get old range, and construct
                    Reference<XTextRange> xStartRange;
                    if (rHelper.FindAndRemoveBookmarkStartRange(xStartRange,
                                                                sName))
                    {
                        Reference<XTextRange> xEndRange(
                            rHelper.GetCursorAsRange()->getStart());

                        // check if beginning and end are in same XText
                        if (xStartRange->getText() == xEndRange->getText())
                        {
                            // create range for insertion
                            Reference<XTextCursor> xInsertionCursor =
                                rHelper.GetText()->createTextCursorByRange(
                                    xEndRange);
                            xInsertionCursor->gotoRange(xStartRange, sal_True);

                            //DBG_ASSERT(! xInsertionCursor->isCollapsed(),
                            //              "we want no point mark");
                            // can't assert, because someone could
                            // create a file with subsequence
                            // start/end elements

                            Reference<XTextRange> xInsertionRange(
                                xInsertionCursor, UNO_QUERY);

                            // insert reference
                            CreateAndInsertMark(GetImport(),
                                                sAPI_bookmark,
                                                sName,
                                                xInsertionRange);
                        }
                        // else: beginning/end in different XText -> ignore!
                    }
                    // else: no start found -> ignore!
                    break;
                }

                case TypeReferenceStart:
                case TypeReferenceEnd:
                    DBG_ERROR("reference start/end are handled in txtparai !");
                    break;

                default:
                    DBG_ERROR("unknown mark type");
                    break;
            }
        }
    }
}

void XMLTextMarkImportContext::CreateAndInsertMark(
    SvXMLImport& rImport,
    const OUString& sServiceName,
    const OUString& sMarkName,
    const Reference<XTextRange> & rRange)
{
    // create mark
    Reference<XMultiServiceFactory> xFactory(rImport.GetModel(),UNO_QUERY);
    if( xFactory.is() )
    {
        Reference<XInterface> xIfc = xFactory->createInstance(sServiceName);

        // set name
        Reference<XNamed> xNamed(xIfc, UNO_QUERY);
        if (xNamed.is())
        {
            xNamed->setName(sMarkName);

            // cast to XTextContent and attach to document
            Reference<XTextContent> xTextContent(xIfc, UNO_QUERY);
            if (xTextContent.is())
            {
                try
                {
                // if inserting marks, bAbsorb==sal_False will cause
                // collapsing of the given XTextRange.
                    rImport.GetTextImport()->GetText()->insertTextContent(rRange,
                        xTextContent, sal_True);
                }
                catch (com::sun::star::lang::IllegalArgumentException e)
                {
                    // ignore
                }
            }
        }
    }
}

sal_Bool XMLTextMarkImportContext::FindName(
    SvXMLImport& rImport,
    const Reference<XAttributeList> & xAttrList,
    OUString& sName)
{
    sal_Bool bNameOK = sal_False;

    // find name attribute first
    sal_Int16 nLength = xAttrList->getLength();
    for(sal_Int16 nAttr = 0; nAttr < nLength; nAttr++)
    {
        OUString sLocalName;
        sal_uInt16 nPrefix = rImport.GetNamespaceMap().
            GetKeyByAttrName( xAttrList->getNameByIndex(nAttr),
                              &sLocalName );

        if ( (XML_NAMESPACE_TEXT == nPrefix) &&
             IsXMLToken(sLocalName, XML_NAME)   )
        {
            sName = xAttrList->getValueByIndex(nAttr);
            bNameOK = sal_True;
        }
    }

    return bNameOK;
}
<|endoftext|>