int diskutil_loop(const char *path, const long long offset, char *lodev, int lodev_size)
{
    int i = 0;
    int ret = EUCA_OK;
    char *ptr = NULL;
    char *output = NULL;
    boolean done = FALSE;
    boolean found = FALSE;
    boolean do_log = FALSE;

    if (path && lodev) {
        // we retry because we cannot atomically obtain a free loopback device on all distros (some
        // versions of 'losetup' allow a file argument with '-f' options, but some do not)
        for (i = 0, done = FALSE, found = FALSE; i < LOOP_RETRIES; i++) {
            sem_p(loop_sem);
            {
                output = pruntf(TRUE, "%s %s -f", helpers_path[ROOTWRAP], helpers_path[LOSETUP]);
            }
            sem_v(loop_sem);

            if (output == NULL) {
                // there was a problem
                break;
            }

            if (strstr(output, "/dev/loop")) {
                strncpy(lodev, output, lodev_size);
                if ((ptr = strrchr(lodev, '\n')) != NULL) {
                    *ptr = '\0';
                    found = TRUE;
                }
            }

            EUCA_FREE(output);

            if (found) {
                do_log = ((i + 1) == LOOP_RETRIES); // log error on last try only
                LOGDEBUG("attaching file %s\n", path);
                LOGDEBUG("            to %s at offset %lld\n", lodev, offset);
                sem_p(loop_sem);
                {
                    char str_offset[64];
                    snprintf(str_offset, sizeof(str_offset), "%lld", offset);
                    output = execlp_output(do_log, helpers_path[ROOTWRAP], helpers_path[LOSETUP], "-o", str_offset, lodev, path, NULL);
                }
                sem_v(loop_sem);

                if (output == NULL) {
                    LOGDEBUG("cannot attach to loop device %s (will retry)\n", lodev);
                } else {
                    EUCA_FREE(output);
                    done = TRUE;
                    break;
                }
            }

            sleep(1);
            found = FALSE;
        }

        if (!done) {
            LOGERROR("cannot find free loop device or attach to one\n");
            ret = EUCA_ERROR;
        }

        return (ret);
    }

    LOGWARN("cannot attach to loop device. path=%s, lodev=%s\n", SP(path), SP(lodev));
    return (EUCA_INVALID_ERROR);
}


static void *createImage_thread(void *arg)
{
    struct createImage_params_t *params = (struct createImage_params_t *)arg;
    ncInstance *instance = params->instance;
    int rc;

    LOGDEBUG("[%s] spawning create-image thread\n", instance->instanceId);
    LOGINFO("[%s] waiting for instance to shut down\n", instance->instanceId);
    // wait until monitor thread changes the state of the instance instance
    if (wait_state_transition(instance, CREATEIMAGE_SHUTDOWN, CREATEIMAGE_SHUTOFF)) {
        if (instance->createImageCanceled) {    // cancel request came in while the instance was shutting down
            LOGINFO("[%s] cancelled while createImage for instance\n", instance->instanceId);
            cleanup_createImage_task(instance, params, SHUTOFF, CREATEIMAGE_CANCELLED);
        } else {
            LOGINFO("[%s] failed while createImage for instance\n", instance->instanceId);
            cleanup_createImage_task(instance, params, SHUTOFF, CREATEIMAGE_FAILED);
        }
        return NULL;
    }

    LOGINFO("[%s] started createImage for instance\n", instance->instanceId);
    {
        rc = 0;
        if (rc == 0) {
            cleanup_createImage_task(instance, params, SHUTOFF, CREATEIMAGE_SUCCESS);
            LOGINFO("[%s] finished createImage for instance\n", instance->instanceId);
        } else if (rc == -1) {
            // bundler child was cancelled (killed)
            cleanup_createImage_task(instance, params, SHUTOFF, CREATEIMAGE_CANCELLED);
            LOGINFO("[%s] cancelled while createImage for instance (rc=%d)\n", instance->instanceId, rc);
        } else {
            cleanup_createImage_task(instance, params, SHUTOFF, CREATEIMAGE_FAILED);
            LOGINFO("[%s] failed while createImage for instance (rc=%d)\n", instance->instanceId, rc);
        }
    }

    return NULL;
}


int shutdown_then_destroy_domain(const char *instanceId)
{
    time_t deadline = 0;
    int error = 0;

    for (boolean done = FALSE; (!done);) {

        virConnectPtr conn = lock_hypervisor_conn();
        if (conn == NULL) {
            LOGERROR("[%s] cannot connect to hypervisor to shut down instance\n", instanceId);
            return -1;
        }

        virDomainPtr dom = virDomainLookupByName(conn, instanceId);
        if (dom == NULL) {             // domain is gone, so we are done
            LOGTRACE("[%s] domain not found\n", instanceId);
            unlock_hypervisor_conn();
            break;
        }

        boolean do_destroy = FALSE;

        if (deadline == 0) {           // first time through the loop
            deadline = time(NULL) + SHUTDOWN_GRACE_PERIOD_SEC;

            // give OS a chance to shut down cleanly
            LOGDEBUG("shutting down instance\n");
            error = virDomainShutdown(dom);
            if (error) {
                do_destroy = TRUE;
            }

        } else if (time(NULL) < deadline) { // within grace period - check on domain
            int dom_status = virDomainIsActive(dom);
            LOGTRACE("domain status '%d'\n", dom_status);
            if (dom_status != 1)       // 1 if running, 0 if inactive, -1 on error
                done = TRUE;

        } else {                       // deadline exceeded
            do_destroy = TRUE;
        }

        if (do_destroy) {
            LOGDEBUG("destroying instance\n");
            error = virDomainDestroy(dom);
            done = TRUE;
        }

        virDomainFree(dom);
        unlock_hypervisor_conn();

        if (!done)
            sleep(2);                  // sleep outside the hypervisor lock
    }

    return error;
}


static int restart_instance(ncInstance * instance)
{
    int error = EUCA_ERROR;
    pthread_attr_t *attr = NULL;

    // Reset a few fields to prevent future confusion
    instance->state = STAGING;
    instance->retries = LIBVIRT_QUERY_RETRIES;
    instance->launchTime = time(NULL);
    //instance->expiryTime           = xxx?
    instance->bootTime = 0;
    instance->bundlingTime = 0;
    instance->createImageTime = 0;
    instance->terminationTime = 0;
    instance->bundlePid = 0;
    instance->bundleCanceled = 0;
    instance->bundleBucketExists = 0;
    instance->stateCode = EXTANT;
    instance->bundleTaskState = NOT_BUNDLING;
    instance->createImageTaskState = NOT_CREATEIMAGE;
    instance->createImagePid = 0;
    instance->createImageCanceled = 0;

    euca_strncpy(instance->stateName, instance_state_names[EXTANT], CHAR_BUFFER_SIZE);
    euca_strncpy(instance->bundleTaskStateName, bundling_progress_names[NOT_BUNDLING], CHAR_BUFFER_SIZE);
    euca_strncpy(instance->createImageTaskStateName, createImage_progress_names[NOT_CREATEIMAGE], CHAR_BUFFER_SIZE);

    // Reset our pthread structure
    memset(&(instance->tcb), 0, sizeof(instance->tcb));

    // to enable NC recovery
    save_instance_struct(instance);

    // do the potentially long tasks in a thread
    if ((attr = (pthread_attr_t *) EUCA_ZALLOC(1, sizeof(pthread_attr_t))) == NULL) {
        LOGERROR("[%s] out of memory\n", instance->instanceId);
        error = EUCA_MEMORY_ERROR;
        goto error;
    }

    pthread_attr_init(attr);
    pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED);

    if (pthread_create(&(instance->tcb), attr, restart_thread, ((void *)instance))) {
        pthread_attr_destroy(attr);
        LOGERROR("[%s] failed to spawn a VM startup thread\n", instance->instanceId);
        error = EUCA_THREAD_ERROR;
        sem_p(inst_sem);
        {
            remove_instance(&global_instances, instance);
            copy_instances();
        }
        sem_v(inst_sem);

        EUCA_FREE(attr);
        goto error;
    }

    pthread_attr_destroy(attr);
    EUCA_FREE(attr);
    return (EUCA_OK);

error:
    free_instance(&instance);
    return (error);
}


static int doDescribeSensors(struct nc_state_t *nc, ncMetadata * pMeta, int historySize, long long collectionIntervalTimeMs, char **instIds,
                             int instIdsLen, char **sensorIds, int sensorIdsLen, sensorResource *** outResources, int *outResourcesLen)
{
    int total;

    int err = sensor_config(historySize, collectionIntervalTimeMs); // update the config parameters if they are different
    if (err != 0)
        LOGERROR("failed to update sensor configuration (err=%d)\n", err);

    sem_p(inst_copy_sem);
    if (instIdsLen == 0)               // describe all instances
        total = total_instances(&global_instances_copy);
    else
        total = instIdsLen;

    sensorResource **rss = NULL;
    if (total > 0) {
        rss = EUCA_ZALLOC(total, sizeof(sensorResource *));
        if (rss == NULL) {
            sem_v(inst_copy_sem);
            return EUCA_MEMORY_ERROR;
        }
    }

    int k = 0;

    ncInstance *instance;
    for (int i = 0; (instance = get_instance(&global_instances_copy)) != NULL; i++) {
        // only pick ones the user (or admin) is allowed to see
        if (strcmp(pMeta->userId, nc->admin_user_id)
            && strcmp(pMeta->userId, instance->userId))
            continue;

        if (instIdsLen > 0) {
            int j;

            for (j = 0; j < instIdsLen; j++)
                if (!strcmp(instance->instanceId, instIds[j]))
                    break;

            if (j >= instIdsLen)
                // instance of no relevance right now
                continue;
        }

        assert(k < total);
        rss[k] = EUCA_ZALLOC(1, sizeof(sensorResource));
        if (sensor_get_instance_data(instance->instanceId, sensorIds, sensorIdsLen, rss + k, 1) != EUCA_OK) {
            LOGDEBUG("[%s] failed to retrieve sensor data\n", instance->instanceId);
            EUCA_FREE(rss[k]);
        } else {
            k++;
        }
    }

    *outResourcesLen = k;
    *outResources = rss;
    sem_v(inst_copy_sem);

    LOGDEBUG("found %d resource(s)\n", k);
    return EUCA_OK;
}


static int doInitialize(struct nc_state_t *nc)
{
    return EUCA_OK;
}


miniwget_getaddr(const char * url, int * size,
                 char * addr, int addrlen, unsigned int scope_id)
{
	unsigned short port;
	char * path;
	/* protocol://host:port/path */
	char hostname[MAXHOSTNAMELEN+1];
	*size = 0;
	if(addr)
		addr[0] = '\0';
	if(!parseURL(url, hostname, &port, &path, &scope_id))
		return NULL;
#ifdef DEBUG
	printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n",
	       hostname, port, path, scope_id);
#endif
	return miniwget2(hostname, port, path, size, addr, addrlen, scope_id);
}


miniwget(const char * url, int * size, unsigned int scope_id)
{
	unsigned short port;
	char * path;
	/* protocol://host:port/chemin */
	char hostname[MAXHOSTNAMELEN+1];
	*size = 0;
	if(!parseURL(url, hostname, &port, &path, &scope_id))
		return NULL;
#ifdef DEBUG
	printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n",
	       hostname, port, path, scope_id);
#endif
	return miniwget2(hostname, port, path, size, 0, 0, scope_id);
}


void DcmSCP::notifyAssociationRequest(const T_ASC_Parameters &params,
                                      DcmSCPActionType & /* desiredAction */)
{
  // Dump some information if required
  DCMNET_INFO("Association Received " << params.DULparams.callingPresentationAddress << ": "
                                      << params.DULparams.callingAPTitle << " -> "
                                      << params.DULparams.calledAPTitle);

    // Dump more information if required
  OFString tempStr;
  if (m_cfg->getVerbosePCMode())
    DCMNET_INFO("Incoming Association Request:" << OFendl << ASC_dumpParameters(tempStr, m_assoc->params, ASC_ASSOC_RQ));
  else
    DCMNET_DEBUG("Incoming Association Request:" << OFendl << ASC_dumpParameters(tempStr, m_assoc->params, ASC_ASSOC_RQ));
}


Uint32 DcmSCP::getMaxReceivePDULength() const
{
  return m_cfg->getMaxReceivePDULength();
}


OFBool DcmSCP::getRefuseAssociation() const
{
  return m_cfg->getRefuseAssociation();
}


OFCondition DcmSCP::addPresentationContext(const OFString &abstractSyntax,
                                           const OFList<OFString> xferSyntaxes,
                                           const T_ASC_SC_ROLE role,
                                           const OFString &profile)
{
  return m_cfg->addPresentationContext(abstractSyntax,xferSyntaxes,role,profile);
}


OFCondition DcmSCP::waitForAssociationRQ(T_ASC_Network *network)
{
  if (network == NULL)
    return ASC_NULLKEY;
  if (m_assoc != NULL)
    return DIMSE_ILLEGALASSOCIATION;

  Uint32 timeout = m_cfg->getConnnectionTimeout();

  // Listen to a socket for timeout seconds and wait for an association request
  OFCondition cond = ASC_receiveAssociation( network, &m_assoc, m_cfg->getMaxReceivePDULength(), NULL, NULL, OFFalse,
                                             m_cfg->getConnectionBlockingMode(), OFstatic_cast(int, timeout) );

  // just return, if timeout occurred (DUL_NOASSOCIATIONREQUEST)
  if ( cond == DUL_NOASSOCIATIONREQUEST )
  {
    return EC_Normal;
  }

  // if error occurs close association and return
  if( cond.bad() )
  {
    dropAndDestroyAssociation();
    return EC_Normal;
  }

  return processAssociationRQ();
}


OFCondition DcmSCP::sendMOVEResponse(const T_ASC_PresentationContextID presID,
                                     const Uint16 messageID,
                                     const OFString &sopClassUID,
                                     DcmDataset *rspDataset,
                                     const Uint16 rspStatusCode,
                                     DcmDataset *statusDetail,
                                     const Uint16 numRemain,
                                     const Uint16 numComplete,
                                     const Uint16 numFail,
                                     const Uint16 numWarn)
{
  OFCondition cond;
  OFString tempStr;

  // Send back response
  T_DIMSE_Message response;
  // Make sure everything is zeroed (especially options)
  bzero((char*)&response, sizeof(response));
  T_DIMSE_C_MoveRSP &moveRsp = response.msg.CMoveRSP;
  response.CommandField = DIMSE_C_MOVE_RSP;
  moveRsp.MessageIDBeingRespondedTo = messageID;
  moveRsp.DimseStatus = rspStatusCode;
  // Always send the optional field "Affected SOP Class UID"
  moveRsp.opts = O_MOVE_AFFECTEDSOPCLASSUID;
  OFStandard::strlcpy(moveRsp.AffectedSOPClassUID, sopClassUID.c_str(), sizeof(moveRsp.AffectedSOPClassUID));
  // Only send the other optional fields if needed
  if ( (numRemain != 0) || (numComplete != 0) || (numFail != 0) || (numWarn != 0) )
  {
    moveRsp.NumberOfRemainingSubOperations = numRemain;
    moveRsp.NumberOfCompletedSubOperations = numComplete;
    moveRsp.NumberOfFailedSubOperations = numFail;
    moveRsp.NumberOfWarningSubOperations = numWarn;
    moveRsp.opts |= O_MOVE_NUMBEROFREMAININGSUBOPERATIONS | O_MOVE_NUMBEROFCOMPLETEDSUBOPERATIONS |
                    O_MOVE_NUMBEROFFAILEDSUBOPERATIONS | O_MOVE_NUMBEROFWARNINGSUBOPERATIONS;
  }

  if (rspDataset)
    moveRsp.DataSetType = DIMSE_DATASET_PRESENT;
  else
    moveRsp.DataSetType = DIMSE_DATASET_NULL;

  if (DCM_dcmnetLogger.isEnabledFor(OFLogger::DEBUG_LOG_LEVEL))
  {
    DCMNET_INFO("Sending C-MOVE Response");
    DCMNET_DEBUG(DIMSE_dumpMessage(tempStr, response, DIMSE_OUTGOING, rspDataset, presID));
  } else {
    DCMNET_INFO("Sending C-MOVE Response (" << DU_cmoveStatusString(rspStatusCode) << ")");
  }

  // Send response message with dataset
  cond = sendDIMSEMessage(presID, &response, rspDataset /* dataObject */, statusDetail);
  if (cond.bad())
  {
    DCMNET_ERROR("Failed sending C-MOVE response: " << DimseCondition::dump(tempStr, cond));
  }

  return cond;
}


void DcmSCP::setHostLookupEnabled(const OFBool mode)
{
  m_cfg->setHostLookupEnabled(mode);
}


static OFCondition echoSCP(T_ASC_Association *assoc, T_DIMSE_C_EchoRQ *req, T_ASC_PresentationContextID presId)
{
    OFLOG_INFO(dcmpsrcvLogger, "Received Echo SCP RQ: MsgID " << req->MessageID);
    OFCondition cond = DIMSE_sendEchoResponse(assoc, presId, req, STATUS_Success, NULL);
    errorCond(cond, "echoSCP: Echo Response Failed:");
    return cond;
}


OFCondition DcmSCP::checkForCANCEL(T_ASC_PresentationContextID presID,
                                   const Uint16 messageID)
{
  return DIMSE_checkForCancelRQ(m_assoc, presID, messageID);
}


refuseAssociation(T_ASC_Association *assoc, refuseReason reason)
{
    T_ASC_RejectParameters rej;

    switch (reason)
    {
    case ref_TooManyAssociations:
        rej.result = ASC_RESULT_REJECTEDTRANSIENT;
        rej.source = ASC_SOURCE_SERVICEPROVIDER_PRESENTATION_RELATED;
        rej.reason = ASC_REASON_SP_PRES_LOCALLIMITEXCEEDED;
        break;
    case ref_CannotFork:
        rej.result = ASC_RESULT_REJECTEDPERMANENT;
        rej.source = ASC_SOURCE_SERVICEPROVIDER_PRESENTATION_RELATED;
        rej.reason = ASC_REASON_SP_PRES_TEMPORARYCONGESTION;
        break;
    case ref_BadAppContext:
        rej.result = ASC_RESULT_REJECTEDTRANSIENT;
        rej.source = ASC_SOURCE_SERVICEUSER;
        rej.reason = ASC_REASON_SU_APPCONTEXTNAMENOTSUPPORTED;
        break;
    case ref_BadAEPeer:
        rej.result = ASC_RESULT_REJECTEDPERMANENT;
        rej.source = ASC_SOURCE_SERVICEUSER;
        rej.reason = ASC_REASON_SU_CALLINGAETITLENOTRECOGNIZED;
        break;
    case ref_BadAEService:
        rej.result = ASC_RESULT_REJECTEDPERMANENT;
        rej.source = ASC_SOURCE_SERVICEUSER;
        rej.reason = ASC_REASON_SU_CALLEDAETITLENOTRECOGNIZED;
        break;
    case ref_NoReason:
    default:
        rej.result = ASC_RESULT_REJECTEDPERMANENT;
        rej.source = ASC_SOURCE_SERVICEUSER;
        rej.reason = ASC_REASON_SU_NOREASON;
        break;
    }

    OFCondition cond = ASC_rejectAssociation(assoc, &rej);
    errorCond(cond, "Association Reject Failed:");
    return cond;
}


OFBool DcmSCP::addStatusDetail(DcmDataset **statusDetail,
                               const DcmElement *elem)
{
  DCMNET_TRACE("Add element to status detail");
  // If no element was passed, return to the caller.
  if( elem == NULL )
    return OFFalse;

  DcmAttributeTag *at;
  DcmLongString *lo;

  // Create the container object if necessary
  if( *statusDetail == NULL )
    *statusDetail = new DcmDataset();

  if (statusDetail == NULL)
  {
    DCMNET_ERROR("Cannot create status detail object, memory exhausted!");
    return OFFalse;
  }

  // Determine the element's data type
  DcmVR vr( elem->ident() );

  // Depending on the element's identification, insert different
  // types of objects into the container.
  switch( elem->ident() )
  {
    case EVR_LO:
      lo = new DcmLongString( *((DcmLongString*)elem) );
      if( lo->getLength() > vr.getMaxValueLength() )
      {
        DCMNET_WARN("Value inside given LO attribute too large for status detail (max " << OFstatic_cast(Uint32, vr.getMaxValueLength()) << ") for " << vr.getVRName());
      }
      (*statusDetail)->insert( lo, OFTrue /*replaceOld*/ );
      // Print debug information
      {
        OFOStringStream oss;
        lo->print(oss);
        OFSTRINGSTREAM_GETSTR(oss, strtemp);
        DCMNET_DEBUG("Adding LO status detail information: " << strtemp);
        OFSTRINGSTREAM_FREESTR(tmpString)
      }
      break;
    case EVR_AT:
      at = new DcmAttributeTag( *((DcmAttributeTag*)elem) );
      if( at->getLength() > vr.getMaxValueLength() )
      {
        DCMNET_WARN("Value inside given AT attribute too large for status detail (max " << OFstatic_cast(Uint32, vr.getMaxValueLength()) << ") for " << vr.getVRName());
      }
      (*statusDetail)->insert( at, OFTrue /*replaceOld*/ );
      // Print debug information
      {
        OFOStringStream oss;
        at->print(oss);
        OFSTRINGSTREAM_GETSTR(oss, strtemp);
        DCMNET_DEBUG("Adding AT status detail information: " << strtemp);
        OFSTRINGSTREAM_FREESTR(tmpString)
      }
      break;
    default:  // other status detail is not supported
      DCMNET_ERROR("Cannot add status detail, unsupported detail attribute type: " << vr.getVRName());
      return OFFalse;
      break;
  }
  return OFTrue;
}


acceptSubAssoc(T_ASC_Network *aNet, T_ASC_Association **assoc)
{
    const char *knownAbstractSyntaxes[] = {
        UID_VerificationSOPClass
    };
    const char *transferSyntaxes[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
    int numTransferSyntaxes;
    OFString temp_str;

    OFCondition cond = ASC_receiveAssociation(aNet, assoc, opt_maxPDU);
    if (cond.good())
    {
      OFLOG_INFO(movescuLogger, "Sub-Association Received");
      OFLOG_DEBUG(movescuLogger, "Parameters:" << OFendl << ASC_dumpParameters(temp_str, (*assoc)->params, ASC_ASSOC_RQ));

      switch (opt_in_networkTransferSyntax)
      {
        case EXS_LittleEndianImplicit:
          /* we only support Little Endian Implicit */
          transferSyntaxes[0] = UID_LittleEndianImplicitTransferSyntax;
          numTransferSyntaxes = 1;
          break;
        case EXS_LittleEndianExplicit:
          /* we prefer Little Endian Explicit */
          transferSyntaxes[0] = UID_LittleEndianExplicitTransferSyntax;
          transferSyntaxes[1] = UID_BigEndianExplicitTransferSyntax;
          transferSyntaxes[2] = UID_LittleEndianImplicitTransferSyntax;
          numTransferSyntaxes = 3;
          break;
        case EXS_BigEndianExplicit:
          /* we prefer Big Endian Explicit */
          transferSyntaxes[0] = UID_BigEndianExplicitTransferSyntax;
          transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
          transferSyntaxes[2] = UID_LittleEndianImplicitTransferSyntax;
          numTransferSyntaxes = 3;
          break;
        case EXS_JPEGProcess14SV1:
          /* we prefer JPEGLossless:Hierarchical-1stOrderPrediction (default lossless) */
          transferSyntaxes[0] = UID_JPEGProcess14SV1TransferSyntax;
          transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
          transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax;
          transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax;
          numTransferSyntaxes = 4;
          break;
        case EXS_JPEGProcess1:
          /* we prefer JPEGBaseline (default lossy for 8 bit images) */
          transferSyntaxes[0] = UID_JPEGProcess1TransferSyntax;
          transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
          transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax;
          transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax;
          numTransferSyntaxes = 4;
          break;
        case EXS_JPEGProcess2_4:
          /* we prefer JPEGExtended (default lossy for 12 bit images) */
          transferSyntaxes[0] = UID_JPEGProcess2_4TransferSyntax;
          transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
          transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax;
          transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax;
          numTransferSyntaxes = 4;
          break;
        case EXS_JPEG2000LosslessOnly:
          /* we prefer JPEG2000 Lossless */
          transferSyntaxes[0] = UID_JPEG2000LosslessOnlyTransferSyntax;
          transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
          transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax;
          transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax;
          numTransferSyntaxes = 4;
          break;
        case EXS_JPEG2000:
          /* we prefer JPEG2000 Lossy */
          transferSyntaxes[0] = UID_JPEG2000TransferSyntax;
          transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
          transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax;
          transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax;
          numTransferSyntaxes = 4;
          break;
        case EXS_JPEGLSLossless:
          /* we prefer JPEG-LS Lossless */
          transferSyntaxes[0] = UID_JPEGLSLosslessTransferSyntax;
          transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
          transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax;
          transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax;
          numTransferSyntaxes = 4;
          break;
        case EXS_JPEGLSLossy:
          /* we prefer JPEG-LS Lossy */
          transferSyntaxes[0] = UID_JPEGLSLossyTransferSyntax;
          transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
          transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax;
          transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax;
          numTransferSyntaxes = 4;
          break;
        case EXS_MPEG2MainProfileAtMainLevel:
          /* we prefer MPEG2 MP@ML */
          transferSyntaxes[0] = UID_MPEG2MainProfileAtMainLevelTransferSyntax;
          transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
          transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax;
          transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax;
          numTransferSyntaxes = 4;
          break;
        case EXS_MPEG2MainProfileAtHighLevel:
          /* we prefer MPEG2 MP@HL */
          transferSyntaxes[0] = UID_MPEG2MainProfileAtHighLevelTransferSyntax;
          transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
          transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax;
          transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax;
          numTransferSyntaxes = 4;
          break;
        case EXS_MPEG4HighProfileLevel4_1:
          /* we prefer MPEG4 HP/L4.1 */
          transferSyntaxes[0] = UID_MPEG4HighProfileLevel4_1TransferSyntax;
          transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
          transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax;
          transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax;
          numTransferSyntaxes = 4;
          break;
        case EXS_MPEG4BDcompatibleHighProfileLevel4_1:
          /* we prefer MPEG4 BD HP/L4.1 */
          transferSyntaxes[0] = UID_MPEG4BDcompatibleHighProfileLevel4_1TransferSyntax;
          transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
          transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax;
          transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax;
          numTransferSyntaxes = 4;
          break;
        case EXS_RLELossless:
          /* we prefer RLE Lossless */
          transferSyntaxes[0] = UID_RLELosslessTransferSyntax;
          transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
          transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax;
          transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax;
          numTransferSyntaxes = 4;
          break;
#ifdef WITH_ZLIB
        case EXS_DeflatedLittleEndianExplicit:
          /* we prefer Deflated Explicit VR Little Endian */
          transferSyntaxes[0] = UID_DeflatedExplicitVRLittleEndianTransferSyntax;
          transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
          transferSyntaxes[2] = UID_BigEndianExplicitTransferSyntax;
          transferSyntaxes[3] = UID_LittleEndianImplicitTransferSyntax;
          numTransferSyntaxes = 4;
          break;
#endif
        default:
          if (opt_acceptAllXfers)
          {
            /* we accept all supported transfer syntaxes
             * (similar to "AnyTransferSyntax" in "storescp.cfg")
             */
            transferSyntaxes[0] = UID_JPEG2000TransferSyntax;
            transferSyntaxes[1] = UID_JPEG2000LosslessOnlyTransferSyntax;
            transferSyntaxes[2] = UID_JPEGProcess2_4TransferSyntax;
            transferSyntaxes[3] = UID_JPEGProcess1TransferSyntax;
            transferSyntaxes[4] = UID_JPEGProcess14SV1TransferSyntax;
            transferSyntaxes[5] = UID_JPEGLSLossyTransferSyntax;
            transferSyntaxes[6] = UID_JPEGLSLosslessTransferSyntax;
            transferSyntaxes[7] = UID_RLELosslessTransferSyntax;
            transferSyntaxes[8] = UID_MPEG2MainProfileAtMainLevelTransferSyntax;
            transferSyntaxes[9] = UID_MPEG2MainProfileAtHighLevelTransferSyntax;
            transferSyntaxes[10] = UID_MPEG4HighProfileLevel4_1TransferSyntax;
            transferSyntaxes[11] = UID_MPEG4BDcompatibleHighProfileLevel4_1TransferSyntax;
            transferSyntaxes[12] = UID_DeflatedExplicitVRLittleEndianTransferSyntax;
            if (gLocalByteOrder == EBO_LittleEndian)
            {
              transferSyntaxes[13] = UID_LittleEndianExplicitTransferSyntax;
              transferSyntaxes[14] = UID_BigEndianExplicitTransferSyntax;
            } else {
              transferSyntaxes[13] = UID_BigEndianExplicitTransferSyntax;
              transferSyntaxes[14] = UID_LittleEndianExplicitTransferSyntax;
            }
            transferSyntaxes[15] = UID_LittleEndianImplicitTransferSyntax;
            numTransferSyntaxes = 16;
          } else {
            /* We prefer explicit transfer syntaxes.
             * If we are running on a Little Endian machine we prefer
             * LittleEndianExplicitTransferSyntax to BigEndianTransferSyntax.
             */
            if (gLocalByteOrder == EBO_LittleEndian)  /* defined in dcxfer.h */
            {
              transferSyntaxes[0] = UID_LittleEndianExplicitTransferSyntax;
              transferSyntaxes[1] = UID_BigEndianExplicitTransferSyntax;
            } else {
              transferSyntaxes[0] = UID_BigEndianExplicitTransferSyntax;
              transferSyntaxes[1] = UID_LittleEndianExplicitTransferSyntax;
            }
            transferSyntaxes[2] = UID_LittleEndianImplicitTransferSyntax;
            numTransferSyntaxes = 3;
          }
          break;

        }

        /* accept the Verification SOP Class if presented */
        cond = ASC_acceptContextsWithPreferredTransferSyntaxes(
            (*assoc)->params,
            knownAbstractSyntaxes, DIM_OF(knownAbstractSyntaxes),
            transferSyntaxes, numTransferSyntaxes);

        if (cond.good())
        {
            /* the array of Storage SOP Class UIDs comes from dcuid.h */
            cond = ASC_acceptContextsWithPreferredTransferSyntaxes(
                (*assoc)->params,
                dcmAllStorageSOPClassUIDs, numberOfAllDcmStorageSOPClassUIDs,
                transferSyntaxes, numTransferSyntaxes);
        }
    }
    if (cond.good())
        cond = ASC_acknowledgeAssociation(*assoc);
    if (cond.good())
    {
        OFLOG_INFO(movescuLogger, "Sub-Association Acknowledged (Max Send PDV: " << (*assoc)->sendPDVLength << ")");
        if (ASC_countAcceptedPresentationContexts((*assoc)->params) == 0)
            OFLOG_INFO(movescuLogger, "    (but no valid presentation contexts)");
        /* dump the presentation contexts which have been accepted/refused */
        OFLOG_DEBUG(movescuLogger, ASC_dumpParameters(temp_str, (*assoc)->params, ASC_ASSOC_AC));
    } else {
        OFLOG_ERROR(movescuLogger, DimseCondition::dump(temp_str, cond));
        ASC_dropAssociation(*assoc);
        ASC_destroyAssociation(assoc);
    }
    return cond;
}


static void executeOnReception()
    /*
     * This function deals with the execution of the command line which was passed
     * to option --exec-on-reception of the storescp. This command line is captured
     * in opt_execOnReception. Note that the command line can contain the placeholders
     * PATH_PLACEHOLDER and FILENAME_PLACEHOLDER which need to be substituted before the command line is actually
     * executed. PATH_PLACEHOLDER will be substituted by the path to the output directory into which
     * the last file was written; FILENAME_PLACEHOLDER will be substituted by the filename of the last
     * file which was written.
     *
     * Parameters:
     *   none.
     */
{
  OFString cmd = opt_execOnReception;

  // in case a file was actually written
  if( !opt_ignore )
  {
    // perform substitution for placeholder #p (depending on presence of any --sort-xxx option)
    OFString dir = (opt_sortStudyMode == ESM_None) ? opt_outputDirectory : subdirectoryPathAndName;
    cmd = replaceChars( cmd, OFString(PATH_PLACEHOLDER), dir );

    // perform substitution for placeholder #f; note that outputFileNameArray.back()
    // always contains the name of the file (without path) which was written last.
    OFString outputFileName = outputFileNameArray.back();
    cmd = replaceChars( cmd, OFString(FILENAME_PLACEHOLDER), outputFileName );
  }

  // perform substitution for placeholder #a
  cmd = replaceChars( cmd, OFString(CALLING_AETITLE_PLACEHOLDER), callingAETitle );

  // perform substitution for placeholder #c
  cmd = replaceChars( cmd, OFString(CALLED_AETITLE_PLACEHOLDER), calledAETitle );

  // perform substitution for placeholder #r
  cmd = replaceChars( cmd, OFString(CALLING_PRESENTATION_ADDRESS_PLACEHOLDER), callingPresentationAddress );

  // Execute command in a new process
  executeCommand( cmd );
}


void DcmSCP::setAETitle(const OFString &aetitle)
{
  m_cfg->setAETitle(aetitle);
}


static void v9fs_attach(void *opaque)
{
    V9fsPDU *pdu = opaque;
    V9fsState *s = pdu->s;
    int32_t fid, afid, n_uname;
    V9fsString uname, aname;
    V9fsFidState *fidp;
    size_t offset = 7;
    V9fsQID qid;
    ssize_t err;

    v9fs_string_init(&uname);
    v9fs_string_init(&aname);
    err = pdu_unmarshal(pdu, offset, "ddssd", &fid,
                        &afid, &uname, &aname, &n_uname);
    if (err < 0) {
        goto out_nofid;
    }
    trace_v9fs_attach(pdu->tag, pdu->id, fid, afid, uname.data, aname.data);

    fidp = alloc_fid(s, fid);
    if (fidp == NULL) {
        err = -EINVAL;
        goto out_nofid;
    }
    fidp->uid = n_uname;
    err = v9fs_co_name_to_path(pdu, NULL, "/", &fidp->path);
    if (err < 0) {
        err = -EINVAL;
        clunk_fid(s, fid);
        goto out;
    }
    err = fid_to_qid(pdu, fidp, &qid);
    if (err < 0) {
        err = -EINVAL;
        clunk_fid(s, fid);
        goto out;
    }
    err = pdu_marshal(pdu, offset, "Q", &qid);
    if (err < 0) {
        clunk_fid(s, fid);
        goto out;
    }
    err += offset;
    memcpy(&s->root_qid, &qid, sizeof(qid));
    trace_v9fs_attach_return(pdu->tag, pdu->id,
                             qid.type, qid.version, qid.path);
    /*
     * disable migration if we haven't done already.
     * attach could get called multiple times for the same export.
     */
    if (!s->migration_blocker) {
        s->root_fid = fid;
        error_setg(&s->migration_blocker,
                   "Migration is disabled when VirtFS export path '%s' is mounted in the guest using mount_tag '%s'",
                   s->ctx.fs_root ? s->ctx.fs_root : "NULL", s->tag);
        migrate_add_blocker(s->migration_blocker);
    }
out:
    put_fid(pdu, fidp);
out_nofid:
    pdu_complete(pdu, err);
    v9fs_string_free(&uname);
    v9fs_string_free(&aname);
}


static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
                                V9fsStatDotl *v9lstat)
{
    memset(v9lstat, 0, sizeof(*v9lstat));

    v9lstat->st_mode = stbuf->st_mode;
    v9lstat->st_nlink = stbuf->st_nlink;
    v9lstat->st_uid = stbuf->st_uid;
    v9lstat->st_gid = stbuf->st_gid;
    v9lstat->st_rdev = stbuf->st_rdev;
    v9lstat->st_size = stbuf->st_size;
    v9lstat->st_blksize = stbuf->st_blksize;
    v9lstat->st_blocks = stbuf->st_blocks;
    v9lstat->st_atime_sec = stbuf->st_atime;
    v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec;
    v9lstat->st_mtime_sec = stbuf->st_mtime;
    v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec;
    v9lstat->st_ctime_sec = stbuf->st_ctime;
    v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec;
    /* Currently we only support BASIC fields in stat */
    v9lstat->st_result_mask = P9_STATS_BASIC;

    stat_to_qid(stbuf, &v9lstat->qid);
}


static int donttouch_stat(V9fsStat *stat)
{
    if (stat->type == -1 &&
        stat->dev == -1 &&
        stat->qid.type == -1 &&
        stat->qid.version == -1 &&
        stat->qid.path == -1 &&
        stat->mode == -1 &&
        stat->atime == -1 &&
        stat->mtime == -1 &&
        stat->length == -1 &&
        !stat->name.size &&
        !stat->uid.size &&
        !stat->gid.size &&
        !stat->muid.size &&
        stat->n_uid == -1 &&
        stat->n_gid == -1 &&
        stat->n_muid == -1) {
        return 1;
    }

    return 0;
}


static bool bsg_complete(struct bsg_device *bd)
{
	bool ret = false;
	bool spin;

	do {
		spin_lock_irq(&bd->lock);

		BUG_ON(bd->done_cmds > bd->queued_cmds);

		/*
		 * All commands consumed.
		 */
		if (bd->done_cmds == bd->queued_cmds)
			ret = true;

		spin = !test_bit(BSG_F_BLOCK, &bd->flags);

		spin_unlock_irq(&bd->lock);
	} while (!ret && spin);

	return ret;
}


int bsg_register_queue(struct request_queue *q, struct device *parent,
		       const char *name, void (*release)(struct device *))
{
	struct bsg_class_device *bcd;
	dev_t dev;
	int ret;
	struct device *class_dev = NULL;
	const char *devname;

	if (name)
		devname = name;
	else
		devname = dev_name(parent);

	/*
	 * we need a proper transport to send commands, not a stacked device
	 */
	if (!queue_is_rq_based(q))
		return 0;

	bcd = &q->bsg_dev;
	memset(bcd, 0, sizeof(*bcd));

	mutex_lock(&bsg_mutex);

	ret = idr_alloc(&bsg_minor_idr, bcd, 0, BSG_MAX_DEVS, GFP_KERNEL);
	if (ret < 0) {
		if (ret == -ENOSPC) {
			printk(KERN_ERR "bsg: too many bsg devices\n");
			ret = -EINVAL;
		}
		goto unlock;
	}

	bcd->minor = ret;
	bcd->queue = q;
	bcd->parent = get_device(parent);
	bcd->release = release;
	kref_init(&bcd->ref);
	dev = MKDEV(bsg_major, bcd->minor);
	class_dev = device_create(bsg_class, parent, dev, NULL, "%s", devname);
	if (IS_ERR(class_dev)) {
		ret = PTR_ERR(class_dev);
		goto put_dev;
	}
	bcd->class_dev = class_dev;

	if (q->kobj.sd) {
		ret = sysfs_create_link(&q->kobj, &bcd->class_dev->kobj, "bsg");
		if (ret)
			goto unregister_class_dev;
	}

	mutex_unlock(&bsg_mutex);
	return 0;

unregister_class_dev:
	device_unregister(class_dev);
put_dev:
	put_device(parent);
	idr_remove(&bsg_minor_idr, bcd->minor);
unlock:
	mutex_unlock(&bsg_mutex);
	return ret;
}


CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy)
{
  struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg:
    &conn->data->state.negotiate;
  char *encoded = NULL;
  size_t len = 0;
  char *userp;
  CURLcode error;

  error = Curl_base64_encode(conn->data,
                             (const char*)neg_ctx->output_token,
                             neg_ctx->output_token_length,
                             &encoded, &len);
  if(error)
    return error;

  if(len == 0)
    return CURLE_REMOTE_ACCESS_DENIED;

  userp = aprintf("%sAuthorization: %s %s\r\n", proxy ? "Proxy-" : "",
                  neg_ctx->protocol, encoded);

  if(proxy)
    conn->allocptr.proxyuserpwd = userp;
  else
    conn->allocptr.userpwd = userp;
  free(encoded);
  return (userp == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK;
}


static bool pickoneauth(struct auth *pick)
{
  bool picked;
  /* only deal with authentication we want */
  unsigned long avail = pick->avail & pick->want;
  picked = TRUE;

  /* The order of these checks is highly relevant, as this will be the order
     of preference in case of the existence of multiple accepted types. */
  if(avail & CURLAUTH_GSSNEGOTIATE)
    pick->picked = CURLAUTH_GSSNEGOTIATE;
  else if(avail & CURLAUTH_DIGEST)
    pick->picked = CURLAUTH_DIGEST;
  else if(avail & CURLAUTH_NTLM)
    pick->picked = CURLAUTH_NTLM;
  else if(avail & CURLAUTH_NTLM_WB)
    pick->picked = CURLAUTH_NTLM_WB;
  else if(avail & CURLAUTH_BASIC)
    pick->picked = CURLAUTH_BASIC;
  else {
    pick->picked = CURLAUTH_PICKNONE; /* we select to use nothing */
    picked = FALSE;
  }
  pick->avail = CURLAUTH_NONE; /* clear it here */

  return picked;
}


get_gss_name(struct connectdata *conn, bool proxy, gss_name_t *server)
{
  struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg:
    &conn->data->state.negotiate;
  OM_uint32 major_status, minor_status;
  gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
  char name[2048];
  const char* service;

  /* GSSAPI implementation by Globus (known as GSI) requires the name to be
     of form "<service>/<fqdn>" instead of <service>@<fqdn> (ie. slash instead
     of at-sign). Also GSI servers are often identified as 'host' not 'khttp'.
     Change following lines if you want to use GSI */

  /* IIS uses the <service>@<fqdn> form but uses 'http' as the service name */

  if(neg_ctx->gss)
    service = "KHTTP";
  else
    service = "HTTP";

  token.length = strlen(service) + 1 + strlen(proxy ? conn->proxy.name :
                                              conn->host.name) + 1;
  if(token.length + 1 > sizeof(name))
    return EMSGSIZE;

  snprintf(name, sizeof(name), "%s@%s", service, proxy ? conn->proxy.name :
           conn->host.name);

  token.value = (void *) name;
  major_status = gss_import_name(&minor_status,
                                 &token,
                                 GSS_C_NT_HOSTBASED_SERVICE,
                                 server);

  return GSS_ERROR(major_status) ? -1 : 0;
}


static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
                       const char *name, FsCred *credp)
{
    int err = -1;
    int dirfd;

    if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE &&
        local_is_mapped_file_metadata(fs_ctx, name)) {
        errno = EINVAL;
        return -1;
    }

    dirfd = local_opendir_nofollow(fs_ctx, dir_path->data);
    if (dirfd == -1) {
        return -1;
    }

    if (fs_ctx->export_flags & V9FS_SM_MAPPED ||
        fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
        err = mkdirat(dirfd, name, SM_LOCAL_DIR_MODE_BITS);
        if (err == -1) {
            goto out;
        }
        credp->fc_mode = credp->fc_mode | S_IFDIR;

        if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
            err = local_set_xattrat(dirfd, name, credp);
        } else {
            err = local_set_mapped_file_attrat(dirfd, name, credp);
        }
        if (err == -1) {
            goto err_end;
        }
    } else if (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH ||
               fs_ctx->export_flags & V9FS_SM_NONE) {
        err = mkdirat(dirfd, name, credp->fc_mode);
        if (err == -1) {
            goto out;
        }
        err = local_set_cred_passthrough(fs_ctx, dirfd, name, credp);
        if (err == -1) {
            goto err_end;
        }
    }
    goto out;

err_end:
    unlinkat_preserve_errno(dirfd, name, AT_REMOVEDIR);
out:
    close_preserve_errno(dirfd);
    return err;
}


void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down)
{
    KeyValue *key = g_new0(KeyValue, 1);
    key->type = KEY_VALUE_KIND_NUMBER;
    key->u.number.data = num;
    qemu_input_event_send_key(src, key, down);
}


static void qemu_input_transform_abs_rotate(InputEvent *evt)
{
    InputMoveEvent *move = evt->u.abs.data;
    switch (graphic_rotate) {
    case 90:
        if (move->axis == INPUT_AXIS_X) {
            move->axis = INPUT_AXIS_Y;
        } else if (move->axis == INPUT_AXIS_Y) {
            move->axis = INPUT_AXIS_X;
            move->value = INPUT_EVENT_ABS_SIZE - 1 - move->value;
        }
        break;
    case 180:
        move->value = INPUT_EVENT_ABS_SIZE - 1 - move->value;
        break;
    case 270:
        if (move->axis == INPUT_AXIS_X) {
            move->axis = INPUT_AXIS_Y;
            move->value = INPUT_EVENT_ABS_SIZE - 1 - move->value;
        } else if (move->axis == INPUT_AXIS_Y) {
            move->axis = INPUT_AXIS_X;
        }
        break;
    }
}


void qemu_input_event_send_key_delay(uint32_t delay_ms)
{
    if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
        return;
    }

    if (!kbd_timer) {
        kbd_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, qemu_input_queue_process,
                                 &kbd_queue);
    }
    if (queue_count < queue_limit) {
        qemu_input_queue_delay(&kbd_queue, kbd_timer,
                               delay_ms ? delay_ms : kbd_default_delay_ms);
    }
}


static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
{
    char buf[1024];
    VncShareMode mode;
    int size;

    mode = data[0] ? VNC_SHARE_MODE_SHARED : VNC_SHARE_MODE_EXCLUSIVE;
    switch (vs->vd->share_policy) {
    case VNC_SHARE_POLICY_IGNORE:
        /*
         * Ignore the shared flag.  Nothing to do here.
         *
         * Doesn't conform to the rfb spec but is traditional qemu
         * behavior, thus left here as option for compatibility
         * reasons.
         */
        break;
    case VNC_SHARE_POLICY_ALLOW_EXCLUSIVE:
        /*
         * Policy: Allow clients ask for exclusive access.
         *
         * Implementation: When a client asks for exclusive access,
         * disconnect all others. Shared connects are allowed as long
         * as no exclusive connection exists.
         *
         * This is how the rfb spec suggests to handle the shared flag.
         */
        if (mode == VNC_SHARE_MODE_EXCLUSIVE) {
            VncState *client;
            QTAILQ_FOREACH(client, &vs->vd->clients, next) {
                if (vs == client) {
                    continue;
                }
                if (client->share_mode != VNC_SHARE_MODE_EXCLUSIVE &&
                    client->share_mode != VNC_SHARE_MODE_SHARED) {
                    continue;
                }
                vnc_disconnect_start(client);
            }
        }
        if (mode == VNC_SHARE_MODE_SHARED) {
            if (vs->vd->num_exclusive > 0) {
                vnc_disconnect_start(vs);
                return 0;
            }
        }
        break;
    case VNC_SHARE_POLICY_FORCE_SHARED:
        /*
         * Policy: Shared connects only.
         * Implementation: Disallow clients asking for exclusive access.
         *
         * Useful for shared desktop sessions where you don't want
         * someone forgetting to say -shared when running the vnc
         * client disconnect everybody else.
         */
        if (mode == VNC_SHARE_MODE_EXCLUSIVE) {
            vnc_disconnect_start(vs);
            return 0;
        }
        break;
    }
    vnc_set_share_mode(vs, mode);

    if (vs->vd->num_shared > vs->vd->connections_limit) {
        vnc_disconnect_start(vs);
        return 0;
    }

    vs->client_width = pixman_image_get_width(vs->vd->server);
    vs->client_height = pixman_image_get_height(vs->vd->server);
    vnc_write_u16(vs, vs->client_width);
    vnc_write_u16(vs, vs->client_height);

    pixel_format_message(vs);

    if (qemu_name) {
        size = snprintf(buf, sizeof(buf), "QEMU (%s)", qemu_name);
        if (size > sizeof(buf)) {
            size = sizeof(buf);
        }
    } else {
        size = snprintf(buf, sizeof(buf), "QEMU");
    }

    vnc_write_u32(vs, size);
    vnc_write(vs, buf, size);
    vnc_flush(vs);

    vnc_client_cache_auth(vs);
    vnc_qmp_event(vs, QAPI_EVENT_VNC_INITIALIZED);

    vnc_read_when(vs, protocol_client_msg, 1);

    return 0;
}


static void vnc_client_cache_addr(VncState *client)
{
    Error *err = NULL;

    client->info = g_malloc0(sizeof(*client->info));
    vnc_init_basic_info_from_remote_addr(client->sioc,
                                         qapi_VncClientInfo_base(client->info),
                                         &err);
    if (err) {
        qapi_free_VncClientInfo(client->info);
        client->info = NULL;
        error_free(err);
    }
}


static void vnc_display_close(VncDisplay *vd)
{
    size_t i;
    if (!vd) {
        return;
    }
    vd->is_unix = false;
    for (i = 0; i < vd->nlsock; i++) {
        if (vd->lsock_tag[i]) {
            g_source_remove(vd->lsock_tag[i]);
        }
        object_unref(OBJECT(vd->lsock[i]));
    }
    g_free(vd->lsock);
    g_free(vd->lsock_tag);
    vd->lsock = NULL;
    vd->lsock_tag = NULL;
    vd->nlsock = 0;

    for (i = 0; i < vd->nlwebsock; i++) {
        if (vd->lwebsock_tag[i]) {
            g_source_remove(vd->lwebsock_tag[i]);
        }
        object_unref(OBJECT(vd->lwebsock[i]));
    }
    g_free(vd->lwebsock);
    g_free(vd->lwebsock_tag);
    vd->lwebsock = NULL;
    vd->lwebsock_tag = NULL;
    vd->nlwebsock = 0;

    vd->auth = VNC_AUTH_INVALID;
    vd->subauth = VNC_AUTH_INVALID;
    if (vd->tlscreds) {
        object_unparent(OBJECT(vd->tlscreds));
        vd->tlscreds = NULL;
    }
    g_free(vd->tlsaclname);
    vd->tlsaclname = NULL;
    if (vd->lock_key_sync) {
        qemu_remove_led_event_handler(vd->led);
        vd->led = NULL;
    }
}


VncInfo *qmp_query_vnc(Error **errp)
{
    VncInfo *info = g_malloc0(sizeof(*info));
    VncDisplay *vd = vnc_display_find(NULL);
    SocketAddress *addr = NULL;

    if (vd == NULL || !vd->nlsock) {
        info->enabled = false;
    } else {
        info->enabled = true;

        /* for compatibility with the original command */
        info->has_clients = true;
        info->clients = qmp_query_client_list(vd);

        if (vd->lsock == NULL) {
            return info;
        }

        addr = qio_channel_socket_get_local_address(vd->lsock[0], errp);
        if (!addr) {
            goto out_error;
        }

        switch (addr->type) {
        case SOCKET_ADDRESS_TYPE_INET:
            info->host = g_strdup(addr->u.inet.host);
            info->service = g_strdup(addr->u.inet.port);
            if (addr->u.inet.ipv6) {
                info->family = NETWORK_ADDRESS_FAMILY_IPV6;
            } else {
                info->family = NETWORK_ADDRESS_FAMILY_IPV4;
            }
            break;

        case SOCKET_ADDRESS_TYPE_UNIX:
            info->host = g_strdup("");
            info->service = g_strdup(addr->u.q_unix.path);
            info->family = NETWORK_ADDRESS_FAMILY_UNIX;
            break;

        case SOCKET_ADDRESS_TYPE_VSOCK:
        case SOCKET_ADDRESS_TYPE_FD:
            error_setg(errp, "Unsupported socket address type %s",
                       SocketAddressType_lookup[addr->type]);
            goto out_error;
        default:
            abort();
        }

        info->has_host = true;
        info->has_service = true;
        info->has_family = true;

        info->has_auth = true;
        info->auth = g_strdup(vnc_auth_name(vd));
    }

    qapi_free_SocketAddress(addr);
    return info;

out_error:
    qapi_free_SocketAddress(addr);
    qapi_free_VncInfo(info);
    return NULL;
}


CalendarRegressionTest::test4100311()
{
    UErrorCode status = U_ZERO_ERROR;
    GregorianCalendar *cal = (GregorianCalendar*)Calendar::createInstance(status);
    if(U_FAILURE(status)) {
      dataerrln("Error creating Calendar: %s", u_errorName(status));
      delete cal;
      return;
    }
    failure(status, "Calendar::createInstance(status)");
    cal->set(UCAL_YEAR, 1997);
    cal->set(UCAL_DAY_OF_YEAR, 1);
    UDate d = cal->getTime(status);             // Should be Jan 1
    failure(status, "cal->getTime");
    logln(UnicodeString("") + d);
    delete cal;
}


CalendarRegressionTest::Test4167060()
{
    UErrorCode status = U_ZERO_ERROR;
    UCalendarDateFields field = UCAL_YEAR;
    DateFormat *format = new SimpleDateFormat(UnicodeString("EEE MMM dd HH:mm:ss zzz yyyy G"),
        Locale::getUS(), status);
    if(U_FAILURE(status)) {
        dataerrln("Couldn't create SimpleDateFormat - %s", u_errorName(status));
        return;
    }

    GregorianCalendar *calendars [] = {
        new GregorianCalendar(100, UCAL_NOVEMBER, 1, status),
        new GregorianCalendar(-99 /*100BC*/, UCAL_JANUARY, 1, status),
        new GregorianCalendar(1996, UCAL_FEBRUARY, 29, status),
    };
    if(U_FAILURE(status)) {
        errln("Couldn't create GregorianCalendars");
        return;
        // could leak
    }

    UnicodeString id [] = { "Hybrid", "Gregorian", "Julian" };

    for (int32_t k=0; k<3; ++k) {
        logln("--- " + id[k] + " ---");

        for (int32_t j=0; j < 3; ++j) {
            GregorianCalendar *calendar = calendars[j];
            if (k == 1) {
                calendar->setGregorianChange(EARLIEST_SUPPORTED_MILLIS, status);
            }
            else if (k == 2) {
                calendar->setGregorianChange(LATEST_SUPPORTED_MILLIS, status);
            }

            if(U_FAILURE(status))
                errln("setGregorianChange() failed");
            format->adoptCalendar((Calendar*)calendar->clone());

            UDate dateBefore = calendar->getTime(status);
            if(U_FAILURE(status))
                errln("getTime() failed");

            int32_t maxYear = calendar->getActualMaximum(field, status);
            UnicodeString temp;
            logln(UnicodeString("maxYear: ") + maxYear + " for " + format->format(calendar->getTime(status), temp));
            temp.remove();
            logln("date before: " + format->format(dateBefore, temp));

            int32_t years[] = {2000, maxYear-1, maxYear, maxYear+1};

            for (int32_t i = 0; i < 4; i++) {
                UBool valid = years[i] <= maxYear;
                calendar->set(field, years[i]);
                UDate dateAfter = calendar->getTime(status);
                if(U_FAILURE(status))
                    errln("getTime() failed");
                int32_t newYear = calendar->get(field, status);
                if(U_FAILURE(status))
                    errln(UnicodeString("get(") + (int32_t)field + ") failed");
                calendar->setTime(dateBefore, status); // restore calendar for next use
                if(U_FAILURE(status))
                    errln("setTime() failed");

                temp.remove();
                logln(UnicodeString(" Year ") + years[i] + (valid? " ok " : " bad") +
                      " => " + format->format(dateAfter, temp));
                if (valid && newYear != years[i]) {
                    errln(UnicodeString("  FAIL: ") + newYear + " should be valid; date, month and time shouldn't change");
                }
                // {sfb} this next line is a hack, but it should work since if a
                // double has an exponent, adding 1 should not yield the same double
                else if (!valid && /*newYear == years[i]*/ dateAfter + 1.0 == dateAfter)  {
                    errln(UnicodeString("  FAIL: ") + newYear + " should be invalid");
                }
            }
        }
    }

    delete format;
    delete calendars[0];
    delete calendars[1];
    delete calendars[2];
}


void CalendarRegressionTest::TestT5555()
{
    UErrorCode ec = U_ZERO_ERROR;
    Calendar *cal = Calendar::createInstance(ec);

    if (cal == NULL || U_FAILURE(ec)) {
        dataerrln("FAIL: Calendar::createInstance(): %s", u_errorName(ec));
        delete cal;
        return;
    }

    // Set to Wednesday, February 21, 2007
    cal->set(2007, UCAL_FEBRUARY, 21);

    // Advance three years
    cal->add(UCAL_MONTH, 36, ec);

    // Set to last Wednesday of the month
    cal->set(UCAL_DAY_OF_WEEK_IN_MONTH, -1);

    cal->getTime(ec);

    int32_t yy, mm, dd, ee;

    yy = cal->get(UCAL_YEAR, ec);
    mm = cal->get(UCAL_MONTH, ec);
    dd = cal->get(UCAL_DATE, ec);
    ee = cal->get(UCAL_DAY_OF_WEEK, ec);

    // Should be set to Wednesday, February 24, 2010
    if (U_FAILURE(ec) || yy != 2010 || mm != UCAL_FEBRUARY || dd != 24 || ee != UCAL_WEDNESDAY) {
        errln("FAIL: got date %4d/%02d/%02d, expected 210/02/24: ", yy, mm + 1, dd);
    }
    delete cal;
}


void CalendarRegressionTest::test4141665()
{
    UErrorCode status = U_ZERO_ERROR;
    GregorianCalendar *cal = new GregorianCalendar(status);
    if(U_FAILURE(status)) {
      dataerrln("Error creating calendar %s", u_errorName(status));
      delete cal;
      return;
    }
    GregorianCalendar *cal2 = (GregorianCalendar*)cal->clone();
    UDate cut = cal->getGregorianChange();
    UDate cut2 = cut + 100*24*60*60*1000.0; // 100 days later
    if (*cal != *cal2) {
        errln("Cloned GregorianCalendars not equal");
    }
    cal2->setGregorianChange(cut2,status);
    if ( *cal == *cal2) {
        errln("GregorianCalendar::equals() ignores cutover");
    }

    delete cal;
    delete cal2;
}


int32_t PersianCalendar::defaultCenturyStartYear() const {
    // lazy-evaluate systemDefaultCenturyStartYear
    umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
    return gSystemDefaultCenturyStartYear;
}


PersianCalendar::inDaylightTime(UErrorCode& status) const
{
    // copied from GregorianCalendar
    if (U_FAILURE(status) || !getTimeZone().useDaylightTime())
        return FALSE;

    // Force an update of the state of the Calendar.
    ((PersianCalendar*)this)->complete(status); // cast away const

    return (UBool)(U_SUCCESS(status) ? (internalGet(UCAL_DST_OFFSET) != 0) : FALSE);
}


UBool PersianCalendar::isLeapYear(int32_t year)
{
    int32_t remainder;
    ClockMath::floorDivide(25 * year + 11, 33, remainder);
    return (remainder < 8);
}


void CalendarRegressionTest::test4051765()
{
    UErrorCode status = U_ZERO_ERROR;
    Calendar *cal = Calendar::createInstance(status);
    if(U_FAILURE(status)) {
      dataerrln("Error creating Calendar: %s", u_errorName(status));
      delete cal;
      return;
    }
    cal->setLenient(FALSE);
    cal->set(UCAL_DAY_OF_WEEK, 0);
    //try {
        cal->getTime(status);
        if( ! U_FAILURE(status))
            errln("Fail: DAY_OF_WEEK 0 should be disallowed");
    /*}
    catch (IllegalArgumentException e) {
        return;
    }*/

    delete cal;
}


int32_t PersianCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const {
    // If the month is out of range, adjust it into range, and
    // modify the extended year value accordingly.
    if (month < 0 || month > 11) {
        extendedYear += ClockMath::floorDivide(month, 12, month);
    }

    return isLeapYear(extendedYear) ? kPersianLeapMonthLength[month] : kPersianMonthLength[month];
}


void* DlfcnModule::findSymbol(const Firebird::string& symName)
{
	void* result = dlsym(module, symName.c_str());
	if (!result)
	{
		Firebird::string newSym = '_' + symName;

		result = dlsym(module, newSym.c_str());
	}

#ifdef HAVE_DLADDR
	if (!PathUtils::isRelative(fileName))
	{
		Dl_info info;
		if (!dladdr(result, &info))
			return NULL;
		if (fileName != info.dli_fname)
			return NULL;
	}
#endif

	return result;
}


DlfcnModule::~DlfcnModule()
{
	if (module)
		dlclose(module);
}


void KrecipesView::createNewElement()
{
	QWidget * vis_panel = rightPanel->visiblePanel();
	if ( vis_panel == ingredientsPanel ) {
		ingredientsPanel->getActionsHandler()->createNew();
	} else if ( vis_panel == propertiesPanel ) {
		propertiesPanel->getActionsHandler()->createNew();
	} else if ( vis_panel == unitsPanel ) {
		if ( unitsPanel->getActionsHandler() )
			unitsPanel->getActionsHandler()->createNew();
	} else if ( vis_panel == prepMethodsPanel ) {
		prepMethodsPanel->getActionsHandler()->createNew();
	} else if ( vis_panel == categoriesPanel) {
		categoriesPanel->getActionsHandler()->createNew();
	} else if ( vis_panel == authorsPanel ) {
		authorsPanel->getActionsHandler()->createNew();
	}
}


void KrecipesView::addElementAction( KAction * action )
{
	ingredientsPanel->addAction( action );
	propertiesPanel->addAction( action );
	unitsPanel->addAction( action );
	prepMethodsPanel->addAction( action );
	categoriesPanel->addAction( action );
	authorsPanel->addAction( action );
}


void KrecipesView::switchToRecipe( void )
{
	slotSetPanel( RecipeEdit );
}


void Krecipes::optionsPreferences()
{

	// popup some sort of preference dialog, here
	QPointer<KrecipesPreferences> dlg = new KrecipesPreferences( this );
	dlg->exec();
	delete dlg;

}


void KrecipesView::categorizeCurrentRecipe()
{
	QWidget * vis_panel = rightPanel->visiblePanel();
	if ( vis_panel == selectPanel ) {
		selectPanel->getActionsHandler()->categorize();
	}
	else if (vis_panel == inputPanel ) {
		inputPanel->addCategory();
	}
}


bool KrecipesView::questionRerunWizard( const QString &message, const QString &errormsg,
	RecipeDB::Error error )
{
	if ( (error == RecipeDB::FixDbFailed) && (dbType == "SQLite") ) {
		QString finalMessage = message + ' ' +
		i18n( "\nYou are using SQLite; this error is often caused by using an SQLite 2 "
		"database with Krecipes supporting SQLite 3, if this is the case you could run "
		"the SQLite converter.\n"
		"What do you want to do?" );
		int answer = KMessageBox::questionYesNoCancel( this, finalMessage, "",
			KGuiItem( i18n("Run the setup assistant"), KIcon("plasmagik") ),
			KGuiItem( i18n("Run the SQLite converter"), KIcon("document-revert") ),
			KStandardGuiItem::quit()
		);
		if ( answer == KMessageBox::Yes ) {
			wizard( true );
		} else if ( answer == KMessageBox::No ) {
			ConvertSQLite3 converter;
			converter.convert();
		} else {
			kError() << errormsg << ". " << i18nc("Exiting Krecipes", "Exiting" ) ;
			kapp->exit( 1 ); exit ( 1 ); //FIXME: why doesn't kapp->exit(1) do anything?
			return false;
		}
		return true;
	} else {
		QString finalMessage = message + ' ' +
		i18n( "\nWould you like to run the setup wizard again? "
		"Otherwise, the application will be closed." );

		int answer = KMessageBox::questionYesNo( this, finalMessage );

		if ( answer == KMessageBox::Yes )
			wizard( true );
		else {
			kError() << errormsg << ". " << i18nc("Exiting Krecipes", "Exiting" ) ;
			kapp->exit( 1 ); exit ( 1 ); //FIXME: why doesn't kapp->exit(1) do anything?
			return false;
		}

		return true;
	}
}


int main( int argc, char **argv )
{
	options.add("convert-sqlite3", ki18n("Convert the current SQLite 2.x database to SQLite 3 and exit") , 0 );
	options.add( 0, KLocalizedString(), 0 );

	KAboutData about( "krecipes", 0, ki18n( "Krecipes" ), version, ki18n( "The KDE Cookbook" ), KAboutData::License_GPL, ki18n( "(C) 2003 Unai Garro\n(C) 2004-2006 Jason Kivlighn"), ki18n("This product is RecipeML compatible.\nYou can get more information about this file format in:\nhttp://www.formatdata.com/recipeml" ), "http://krecipes.sourceforge.net/", "panfaust@gmail.com" );
	about.addAuthor( ki18n("Unai Garro"), KLocalizedString(), "ugarro@gmail.com", 0 );
	about.addAuthor( ki18n("Jason Kivlighn"), KLocalizedString(), "jkivlighn@gmail.com", 0 );
	about.addAuthor( ki18n("Cyril Bosselut"), KLocalizedString(), "bosselut@b1project.com", "http://b1project.com" );

	about.addCredit( ki18n("Colleen Beamer"), ki18n("Testing, bug reports, suggestions"), "colleen.beamer@gmail.com", 0 );
	about.addCredit( ki18n("Robert Wadley"), ki18n("Icons and artwork"), "rob@robntina.fastmail.us", 0 );
	about.addAuthor( ki18n("Daniel Sauvé"), ki18n("Porting to KDE4"), "megametres@gmail.com", "http://metres.homelinux.com" );

        about.addAuthor( ki18n("Laurent Montel"), ki18n("Porting to KDE4"), "montel@kde.org", 0 );
        about.addAuthor( ki18n("José Manuel Santamaría Lema"), ki18n("Porting to KDE4, current maintainer"), "panfaust@gmail.com", 0 );
        about.addAuthor( ki18n("Martin Engelmann"), ki18n("Porting to KDE4, developer"), "murphi.oss@googlemail.com", 0 );

	about.addCredit( ki18n("Patrick Spendrin"), ki18n("Patches to make Krecipes work under Windows"), "ps_ml@gmx.de", 0 );
	about.addCredit( ki18n("Mike Ferguson"), ki18n("Help with bugs, patches"), "", 0 );
	about.addCredit( ki18n("Warren Severin"), ki18n("Code to export recipes to *.mx2 files"), "", 0 );

	about.addCredit( ki18n("Eduardo Robles Elvira"),
		ki18n("He adviced using WebKit to fix printing support during Akademy-es 2010."),
		"edulix@gmail.com", 0 );
	about.addCredit( ki18n("José Millán Soto"),
		ki18n("He adviced using WebKit to fix printing support during Akademy-es 2010."),
		"", 0 );

	about.setTranslator( ki18n( "INSERT YOUR NAME HERE" ), ki18n( "INSERT YOUR EMAIL ADDRESS" ) );
	KCmdLineArgs::init( argc, argv, &about );
	KCmdLineArgs::addCmdLineOptions( options );
	KUniqueApplication::addCmdLineOptions();

	if ( !KUniqueApplication::start() ) {
		std::cerr << "Krecipes is already running!" << std::endl;
		return 0;
	}

	KUniqueApplication app;

	// see if we are starting with session management
	if ( app.isSessionRestored() ) {
		RESTORE( Krecipes );
	}
	else {
		// no session.. just start up normally
		KCmdLineArgs *args = KCmdLineArgs::parsedArgs();

		QApplication::flush();

		if ( args->isSet("convert-sqlite3") ) {
			ConvertSQLite3 sqliteConverter;
			sqliteConverter.convert();
			return 0;
		}

		Krecipes * widget = new Krecipes;
		app.setTopWidget( widget );
		widget->show();

		args->clear();
	}

	return app.exec();
}


ffi_closure_free (void *ptr)
{
#if FFI_CLOSURE_FREE_CODE
  msegmentptr seg = segment_holding_code (gm, ptr);

  if (seg)
    ptr = sub_segment_exec_offset (ptr, seg);
#endif

  dlfree (ptr);
}


    sizeof(max_align_t)
    : sizeof(void *) + sizeof(size_t);

#define ADD_TO_POINTER(p, d) ((void *)((uintptr_t)(p) + (d)))

void *
ffi_closure_alloc (size_t size, void **code)
{
  static size_t page_size;
  size_t rounded_size;
  void *codeseg, *dataseg;
  int prot;

  /* Expect that PAX mprotect is active and a separate code mapping is necessary. */
  if (!code)
    return NULL;

  /* Obtain system page size. */
  if (!page_size)
    page_size = sysconf(_SC_PAGESIZE);

  /* Round allocation size up to the next page, keeping in mind the size field and pointer to code map. */
  rounded_size = (size + overhead + page_size - 1) & ~(page_size - 1);

  /* Primary mapping is RW, but request permission to switch to PROT_EXEC later. */
  prot = PROT_READ | PROT_WRITE | PROT_MPROTECT(PROT_EXEC);
  dataseg = mmap(NULL, rounded_size, prot, MAP_ANON | MAP_PRIVATE, -1, 0);
  if (dataseg == MAP_FAILED)
    return NULL;

  /* Create secondary mapping and switch it to RX. */
  codeseg = mremap(dataseg, rounded_size, NULL, rounded_size, MAP_REMAPDUP);
  if (codeseg == MAP_FAILED) {
    munmap(dataseg, rounded_size);
    return NULL;
  }
  if (mprotect(codeseg, rounded_size, PROT_READ | PROT_EXEC) == -1) {
    munmap(codeseg, rounded_size);
    munmap(dataseg, rounded_size);
    return NULL;
  }

  /* Remember allocation size and location of the secondary mapping for ffi_closure_free. */
  memcpy(dataseg, &rounded_size, sizeof(rounded_size));
  memcpy(ADD_TO_POINTER(dataseg, sizeof(size_t)), &codeseg, sizeof(void *));
  *code = ADD_TO_POINTER(codeseg, overhead);
  return ADD_TO_POINTER(dataseg, overhead);
}


ffi_clear_cache (void *start, void *end)
{
#if defined (__clang__) && defined (__APPLE__)
  sys_icache_invalidate (start, (char *)end - (char *)start);
#elif defined (__GNUC__)
  __builtin___clear_cache (start, end);
#else
#error "Missing builtin to flush instruction cache"
#endif
}


allocate_to_stack (struct arg_state *state, void *stack,
		   size_t alignment, size_t size)
{
  size_t nsaa = state->nsaa;

  /* Round up the NSAA to the larger of 8 or the natural
     alignment of the argument's type.  */
#if defined (__APPLE__)
  if (state->allocating_variadic && alignment < 8)
    alignment = 8;
#else
  if (alignment < 8)
    alignment = 8;
#endif

  nsaa = FFI_ALIGN (nsaa, alignment);
  state->nsaa = nsaa + size;

  return (char *)stack + nsaa;
}


print_precedence_warnings (void)
{
  if (!prec_nodes)
    init_prec_nodes ();
  if (!used_assoc)
    init_assoc ();
  for (int i = 0; i < nsyms; ++i)
    {
      symbol *s = symbols[i];
      if (s
          && s->content->prec != 0
          && !prec_nodes[i]->pred
          && !prec_nodes[i]->succ)
        {
          if (is_assoc_useless (s))
            complain (&s->content->prec_loc, Wprecedence,
                      _("useless precedence and associativity for %s"), s->tag);
          else if (s->content->assoc == precedence_assoc)
            complain (&s->content->prec_loc, Wprecedence,
                      _("useless precedence for %s"), s->tag);
        }
      else if (is_assoc_useless (s))
        complain (&s->content->prec_loc, Wprecedence,
                  _("useless associativity for %s, use %%precedence"), s->tag);
    }
  free (used_assoc);
  assoc_free ();
}


symbol_cmp (void const *a, void const *b)
{
  return location_cmp ((*(symbol * const *)a)->location,
                       (*(symbol * const *)b)->location);
}


complain_symbol_redeclared (symbol *s, const char *what, location first,
                            location second)
{
  locations_sort (&first, &second);
  complain (&second, complaint, _("%s redeclaration for %s"), what, s->tag);
  subcomplain (&first, complaint, _("previous declaration"));
}


is_assoc_useless (symbol *s)
{
  return s
      && s->content->assoc != undef_assoc
      && s->content->assoc != precedence_assoc
      && !used_assoc[s->content->number];
}


symbols_check_defined (void)
{
  table_sort (symbol_table, &symbols_sorted);
  /* semantic_type, like symbol, starts with a 'tag' field and then a
     'location' field.  And here we only deal with arrays/hashes of
     pointers, sizeof is not an issue.

     So instead of implementing table_sort (and symbol_cmp) once for
     each type, let's lie a bit to the typing system, and treat
     'semantic_type' as if it were 'symbol'. */
  table_sort (semantic_type_table, (symbol ***) &semantic_types_sorted);

  for (int i = 0; symbols_sorted[i]; ++i)
    symbol_check_defined (symbols_sorted[i]);
  for (int i = 0; semantic_types_sorted[i]; ++i)
    semantic_type_check_defined (semantic_types_sorted[i]);
}


grammar_midrule_action (void)
{
  /* Since the action was written out with this rule's number, we must
     give the new rule this number by inserting the new rule before
     it.  */

  /* Make a DUMMY nonterminal, whose location is that of the midrule
     action.  Create the MIDRULE.  */
  location dummy_loc = current_rule->action_props.location;
  symbol *dummy = dummy_symbol_get (dummy_loc);
  symbol_type_set (dummy,
                   current_rule->action_props.type, current_rule->action_props.location);
  symbol_list *midrule = symbol_list_sym_new (dummy, dummy_loc);

  /* Remember named_ref of previous action. */
  named_ref *action_name = current_rule->action_props.named_ref;

  /* Make a new rule, whose body is empty, before the current one, so
     that the action just read can belong to it.  */
  ++nrules;
  ++nritems;
  /* Attach its location and actions to that of the DUMMY.  */
  midrule->rhs_loc = dummy_loc;
  code_props_rule_action_init (&midrule->action_props,
                               current_rule->action_props.code,
                               current_rule->action_props.location,
                               midrule,
                               /* name_ref */ NULL,
                               /* type */ NULL,
                               current_rule->action_props.is_predicate);
  code_props_none_init (&current_rule->action_props);

  midrule->expected_sr_conflicts = current_rule->expected_sr_conflicts;
  midrule->expected_rr_conflicts = current_rule->expected_rr_conflicts;
  current_rule->expected_sr_conflicts = -1;
  current_rule->expected_rr_conflicts = -1;

  if (previous_rule_end)
    previous_rule_end->next = midrule;
  else
    grammar = midrule;

  /* End the dummy's rule.  */
  midrule->next = symbol_list_sym_new (NULL, dummy_loc);
  midrule->next->next = current_rule;

  previous_rule_end = midrule->next;

  /* Insert the dummy nonterminal replacing the midrule action into
     the current rule.  Bind it to its dedicated rule.  */
  grammar_current_rule_symbol_append (dummy, dummy_loc,
                                      action_name);
  grammar_end->midrule = midrule;
  midrule->midrule_parent_rule = current_rule;
  midrule->midrule_parent_rhs_index = symbol_list_length (current_rule->next);
}


grammar_current_rule_predicate_append (const char *pred, location loc)
{
  if (current_rule->action_props.code)
    grammar_midrule_action ();
  code_props_rule_action_init (&current_rule->action_props, pred, loc,
                               current_rule,
                               NULL, NULL,
                               /* is_predicate */ true);
}


table_sort (struct hash_table *table, symbol ***sorted)
{
  aver (!*sorted);
  size_t count = hash_get_n_entries (table);
  *sorted = xnmalloc (count + 1, sizeof **sorted);
  hash_get_entries (table, (void**)*sorted, count);
  qsort (*sorted, count, sizeof **sorted, symbol_cmp);
  (*sorted)[count] = NULL;
}


grammar_current_rule_begin (symbol *lhs, location loc,
                            named_ref *lhs_name)
{
  /* Start a new rule and record its lhs.  */
  ++nrules;
  previous_rule_end = grammar_end;

  current_rule = grammar_symbol_append (lhs, loc);
  if (lhs_name)
    assign_named_ref (current_rule, named_ref_copy (lhs_name));

  /* Mark the rule's lhs as a nonterminal if not already so.  */
  if (lhs->content->class == unknown_sym || lhs->content->class == pct_type_sym)
    symbol_class_set (lhs, nterm_sym, empty_loc, false);
  else if (lhs->content->class == token_sym)
    complain (&loc, complaint, _("rule given for %s, which is a token"),
              lhs->tag);
}


assoc_free (void)
{
  for (int i = 0; i < nsyms; ++i)
    {
      linkedlist_free (prec_nodes[i]->pred);
      linkedlist_free (prec_nodes[i]->succ);
      free (prec_nodes[i]);
    }
  free (prec_nodes);
}


register_assoc (graphid i, graphid j)
{
  if (!used_assoc)
    init_assoc ();
  used_assoc[i] = true;
  used_assoc[j] = true;
}


complain_pct_type_on_token (location *loc)
{
  complain (loc, Wyacc,
            _("POSIX yacc reserves %%type to nonterminals"));
}


semantic_type_new (uniqstr tag, const location *loc)
{
  semantic_type *res = xmalloc (sizeof *res);

  uniqstr_assert (tag);
  res->tag = tag;
  res->location = loc ? *loc : empty_loc;
  res->status = undeclared;
  for (int i = 0; i < CODE_PROPS_SIZE; ++i)
    code_props_none_init (&res->props[i]);

  return res;
}


nbd_unlocked_aio_pwrite (struct nbd_handle *h, const void *buf,
                         size_t count, uint64_t offset,
                         nbd_completion_callback *completion,
                         uint32_t flags)
{
  struct command_cb cb = { .completion = *completion };

  if (h->strict & LIBNBD_STRICT_COMMANDS) {
    if (nbd_unlocked_is_read_only (h) == 1) {
      set_error (EPERM, "server does not support write operations");
      return -1;
    }

    if ((flags & LIBNBD_CMD_FLAG_FUA) != 0 &&
        nbd_unlocked_can_fua (h) != 1) {
      set_error (EINVAL, "server does not support the FUA flag");
      return -1;
    }
  }

  SET_CALLBACK_TO_NULL (*completion);
  return nbd_internal_command_common (h, flags, NBD_CMD_WRITE, offset, count,
                                      ENOSPC, (void *) buf, &cb);
}


nbd_unlocked_aio_block_status (struct nbd_handle *h,
                               uint64_t count, uint64_t offset,
                               nbd_extent_callback *extent,
                               nbd_completion_callback *completion,
                               uint32_t flags)
{
  struct command_cb cb = { .fn.extent = *extent,
                           .completion = *completion };

  if (h->strict & LIBNBD_STRICT_COMMANDS) {
    if (!h->structured_replies) {
      set_error (ENOTSUP, "server does not support structured replies");
      return -1;
    }

    if (h->meta_contexts == NULL) {
      set_error (ENOTSUP, "did not negotiate any metadata contexts, "
                 "either you did not call nbd_add_meta_context before "
                 "connecting or the server does not support it");
      return -1;
    }
  }

  SET_CALLBACK_TO_NULL (*extent);
  SET_CALLBACK_TO_NULL (*completion);
  return nbd_internal_command_common (h, flags, NBD_CMD_BLOCK_STATUS, offset,
                                      count, EINVAL, NULL, &cb);
}


nbd_unlocked_get_private_data (struct nbd_handle *h)
{
  return h->private_data;
}


nbd_unlocked_set_full_info (struct nbd_handle *h, bool request)
{
  h->full_info = request;
  return 0;
}


nbd_unlocked_get_export_description (struct nbd_handle *h)
{
  char *r;

  if (h->eflags == 0) {
    set_error (EINVAL, "server has not returned export flags, "
               "you need to connect to the server first");
    return NULL;
  }
  if (h->description == NULL) {
    set_error (ENOTSUP, "server did not advertise a description");
    return NULL;
  }

  r = strdup (h->description);
  if (r == NULL) {
    set_error (errno, "strdup");
    return NULL;
  }
  return r;
}


nbd_unlocked_get_handle_name (struct nbd_handle *h)
{
  char *copy = strdup (h->hname);

  if (!copy) {
    set_error (errno, "strdup");
    return NULL;
  }

  return copy;
}


void dwgRSCodec::decode239I(unsigned char *in, unsigned char *out, duint32 blk){
    int k=0;
    unsigned char data[255];
    RScodec rsc(0x96, 8, 8); //(255, 239)
    for (duint32 i=0; i<blk; i++){
        k = i;
        for (int j=0; j<255; j++) {
            data[j] = in[k];
            k +=blk;
        }
        int r = rsc.decode(data);
        if (r<0)
            DRW_DBG("\nWARNING: dwgRSCodec::decode239I, can't correct all errors");
        k = i*239;
        for (int j=0; j<239; j++) {
            out[k++] = data[j];
        }
    }
}


bool DRW_Vport::parseDwg(DRW::Version version, dwgBuffer *buf, duint32 bs){
    dwgBuffer sBuff = *buf;
    dwgBuffer *sBuf = buf;
    if (version > DRW::AC1018) {//2007+
        sBuf = &sBuff; //separate buffer for strings
    }
    bool ret = DRW_TableEntry::parseDwg(version, buf, sBuf, bs);
    DRW_DBG("\n***************************** parsing VPort ************************************************\n");
    if (!ret)
        return ret;
    name = sBuf->getVariableText(version, false);
    DRW_DBG("vport name: "); DRW_DBG(name.c_str()); DRW_DBG("\n");
    flags |= buf->getBit()<< 6;// code 70, bit 7 (64)
    if (version < DRW::AC1021) { //2004-
        /*dint16 xrefindex =*/ buf->getBitShort();
    }
    flags |= buf->getBit() << 4; //is refx dependent, style code 70, bit 5 (16)
    height = buf->getBitDouble();
    ratio = buf->getBitDouble();
    DRW_DBG("flags: "); DRW_DBG(flags); DRW_DBG(" height: "); DRW_DBG(height);
    DRW_DBG(" ratio: "); DRW_DBG(ratio);
    center = buf->get2RawDouble();
    DRW_DBG("\nview center: "); DRW_DBGPT(center.x, center.y, center.z);
    viewTarget.x = buf->getBitDouble();
    viewTarget.y = buf->getBitDouble();
    viewTarget.z = buf->getBitDouble();
    DRW_DBG("\nview target: "); DRW_DBGPT(viewTarget.x, viewTarget.y, viewTarget.z);
    viewDir.x = buf->getBitDouble();
    viewDir.y = buf->getBitDouble();
    viewDir.z = buf->getBitDouble();
    DRW_DBG("\nview dir: "); DRW_DBGPT(viewDir.x, viewDir.y, viewDir.z);
    twistAngle = buf->getBitDouble();
    lensHeight = buf->getBitDouble();
    frontClip = buf->getBitDouble();
    backClip = buf->getBitDouble();
    DRW_DBG("\ntwistAngle: "); DRW_DBG(twistAngle); DRW_DBG(" lensHeight: "); DRW_DBG(lensHeight);
    DRW_DBG(" frontClip: "); DRW_DBG(frontClip); DRW_DBG(" backClip: "); DRW_DBG(backClip);
    viewMode = buf->getBit(); //view mode, code 71, bit 0 (1)
    viewMode |= buf->getBit() << 1; //view mode, code 71, bit 1 (2)
    viewMode |= buf->getBit() << 2; //view mode, code 71, bit 2 (4)
    viewMode |= buf->getBit() << 4; //view mode, code 71, bit 4 (16)
    if (version > DRW::AC1014) { //2000+
        //duint8 renderMode = buf->getRawChar8();
        DRW_DBG("\n renderMode: "); DRW_DBG(buf->getRawChar8());
        if (version > DRW::AC1018) { //2007+
            DRW_DBG("\n use default lights: "); DRW_DBG(buf->getBit());
            DRW_DBG(" default lighting type: "); DRW_DBG(buf->getRawChar8());
            DRW_DBG(" brightness: "); DRW_DBG(buf->getBitDouble());
            DRW_DBG("\n contrast: "); DRW_DBG(buf->getBitDouble()); DRW_DBG("\n");
            DRW_DBG(" ambient color CMC: "); DRW_DBG(buf->getCmColor(version));
        }
    }
    lowerLeft = buf->get2RawDouble();
    DRW_DBG("\nlowerLeft: "); DRW_DBGPT(lowerLeft.x, lowerLeft.y, lowerLeft.z);
    UpperRight = buf->get2RawDouble();
    DRW_DBG("\nUpperRight: "); DRW_DBGPT(UpperRight.x, UpperRight.y, UpperRight.z);
    viewMode |= buf->getBit() << 3; //UCSFOLLOW, view mode, code 71, bit 3 (8)
    circleZoom = buf->getBitShort();
    fastZoom = buf->getBit();
    DRW_DBG("\nviewMode: "); DRW_DBG(viewMode); DRW_DBG(" circleZoom: ");
    DRW_DBG(circleZoom); DRW_DBG(" fastZoom: "); DRW_DBG(fastZoom);
    ucsIcon = buf->getBit(); //ucs Icon, code 74, bit 0 (1)
    ucsIcon |= buf->getBit() << 1; //ucs Icon, code 74, bit 1 (2)
    grid = buf->getBit();
    DRW_DBG("\nucsIcon: "); DRW_DBG(ucsIcon); DRW_DBG(" grid: "); DRW_DBG(grid);
    gridSpacing = buf->get2RawDouble();
    DRW_DBG("\ngrid Spacing: "); DRW_DBGPT(gridSpacing.x, gridSpacing.y, gridSpacing.z);
    snap = buf->getBit();
    snapStyle = buf->getBit();
    DRW_DBG("\nsnap on/off: "); DRW_DBG(snap); DRW_DBG(" snap Style: "); DRW_DBG(snapStyle);
    snapIsopair = buf->getBitShort();
    snapAngle = buf->getBitDouble();
    DRW_DBG("\nsnap Isopair: "); DRW_DBG(snapIsopair); DRW_DBG(" snap Angle: "); DRW_DBG(snapAngle);
    snapBase = buf->get2RawDouble();
    DRW_DBG("\nsnap Base: "); DRW_DBGPT(snapBase.x, snapBase.y, snapBase.z);
    snapSpacing = buf->get2RawDouble();
    DRW_DBG("\nsnap Spacing: "); DRW_DBGPT(snapSpacing.x, snapSpacing.y, snapSpacing.z);
    if (version > DRW::AC1014) { //2000+
        DRW_DBG("\n Unknown: "); DRW_DBG(buf->getBit());
        DRW_DBG(" UCS per Viewport: "); DRW_DBG(buf->getBit());
        DRW_DBG("\nUCS origin: "); DRW_DBGPT(buf->getBitDouble(), buf->getBitDouble(), buf->getBitDouble());
        DRW_DBG("\nUCS X Axis: "); DRW_DBGPT(buf->getBitDouble(), buf->getBitDouble(), buf->getBitDouble());
        DRW_DBG("\nUCS Y Axis: "); DRW_DBGPT(buf->getBitDouble(), buf->getBitDouble(), buf->getBitDouble());
        DRW_DBG("\nUCS elevation: "); DRW_DBG(buf->getBitDouble());
        DRW_DBG(" UCS Orthographic type: "); DRW_DBG(buf->getBitShort());
        if (version > DRW::AC1018) { //2007+
            gridBehavior = buf->getBitShort();
            DRW_DBG(" gridBehavior (flags): "); DRW_DBG(gridBehavior);
            DRW_DBG(" Grid major: "); DRW_DBG(buf->getBitShort());
        }
    }

    //common handles
    if (version > DRW::AC1018) {//2007+ skip string area
        buf->setPosition(objSize >> 3);
        buf->setBitPos(objSize & 7);
    }
    dwgHandle vpControlH = buf->getHandle();
    DRW_DBG("\n parentControlH Handle: "); DRW_DBGHL(vpControlH.code, vpControlH.size, vpControlH.ref); DRW_DBG("\n");
    parentHandle = vpControlH.ref;
    DRW_DBG("Remaining bytes: "); DRW_DBG(buf->numRemainingBytes()); DRW_DBG("\n");
    if (xDictFlag !=1){
        dwgHandle XDicObjH = buf->getHandle();
        DRW_DBG(" XDicObj control Handle: "); DRW_DBGHL(XDicObjH.code, XDicObjH.size, XDicObjH.ref); DRW_DBG("\n");
        DRW_DBG("Remaining bytes: "); DRW_DBG(buf->numRemainingBytes()); DRW_DBG("\n");
    }
/*RLZ: fails verify this part*/    dwgHandle XRefH = buf->getHandle();
    DRW_DBG(" XRefH control Handle: "); DRW_DBGHL(XRefH.code, XRefH.size, XRefH.ref);

    if (version > DRW::AC1014) { //2000+
        DRW_DBG("\nRemaining bytes: "); DRW_DBG(buf->numRemainingBytes());
        if (version > DRW::AC1018) { //2007+
            dwgHandle bkgrdH = buf->getHandle();
            DRW_DBG(" background Handle: "); DRW_DBGHL(bkgrdH.code, bkgrdH.size, bkgrdH.ref);
            DRW_DBG("\nRemaining bytes: "); DRW_DBG(buf->numRemainingBytes());
            dwgHandle visualStH = buf->getHandle();
            DRW_DBG(" visual style Handle: "); DRW_DBGHL(visualStH.code, visualStH.size, visualStH.ref);
            DRW_DBG("\nRemaining bytes: "); DRW_DBG(buf->numRemainingBytes());
            dwgHandle sunH = buf->getHandle();
            DRW_DBG(" sun Handle: "); DRW_DBGHL(sunH.code, sunH.size, sunH.ref);
            DRW_DBG("\nRemaining bytes: "); DRW_DBG(buf->numRemainingBytes());
        }
        dwgHandle namedUCSH = buf->getHandle();
        DRW_DBG(" named UCS Handle: "); DRW_DBGHL(namedUCSH.code, namedUCSH.size, namedUCSH.ref);
        DRW_DBG("\nRemaining bytes: "); DRW_DBG(buf->numRemainingBytes());
        dwgHandle baseUCSH = buf->getHandle();
        DRW_DBG(" base UCS Handle: "); DRW_DBGHL(baseUCSH.code, baseUCSH.size, baseUCSH.ref);
    }

    DRW_DBG("\n Remaining bytes: "); DRW_DBG(buf->numRemainingBytes()); DRW_DBG("\n");
    //    RS crc;   //RS */
    return buf->isGood();
}


    void reset(){
        tType = DRW::IMAGEDEF;
        imgVersion = 0;
        DRW_TableEntry::reset();
    }


static int lexclass(struct cstate *g)
{
	int type = L_CCLASS;
	int quoted, havesave, havedash;
	Rune save = 0;

	newcclass(g);

	quoted = nextrune(g);
	if (!quoted && g->yychar == '^') {
		type = L_NCCLASS;
		quoted = nextrune(g);
	}

	havesave = havedash = 0;
	for (;;) {
		if (g->yychar == EOF)
			die(g, "unterminated character class");
		if (!quoted && g->yychar == ']')
			break;

		if (!quoted && g->yychar == '-') {
			if (havesave) {
				if (havedash) {
					addrange(g, save, '-');
					havesave = havedash = 0;
				} else {
					havedash = 1;
				}
			} else {
				save = '-';
				havesave = 1;
			}
		} else if (quoted && strchr("DSWdsw", g->yychar)) {
			if (havesave) {
				addrange(g, save, save);
				if (havedash)
					addrange(g, '-', '-');
			}
			switch (g->yychar) {
			case 'd': addranges_d(g); break;
			case 's': addranges_s(g); break;
			case 'w': addranges_w(g); break;
			case 'D': addranges_D(g); break;
			case 'S': addranges_S(g); break;
			case 'W': addranges_W(g); break;
			}
			havesave = havedash = 0;
		} else {
			if (quoted) {
				if (g->yychar == 'b')
					g->yychar = '\b';
				else if (g->yychar == '0')
					g->yychar = 0;
				/* else identity escape */
			}
			if (havesave) {
				if (havedash) {
					addrange(g, save, g->yychar);
					havesave = havedash = 0;
				} else {
					addrange(g, save, save);
					save = g->yychar;
				}
			} else {
				save = g->yychar;
				havesave = 1;
			}
		}

		quoted = nextrune(g);
	}

	if (havesave) {
		addrange(g, save, save);
		if (havedash)
			addrange(g, '-', '-');
	}

	return type;
}


static int count(struct cstate *g, Renode *node, int depth)
{
	int min, max, n;
	if (!node) return 0;
	if (++depth > REG_MAXREC) die(g, "stack overflow");
	switch (node->type) {
	default: return 1;
	case P_CAT: return count(g, node->x, depth) + count(g, node->y, depth);
	case P_ALT: return count(g, node->x, depth) + count(g, node->y, depth) + 2;
	case P_REP:
		min = node->m;
		max = node->n;
		if (min == max) n = count(g, node->x, depth) * min;
		else if (max < REPINF) n = count(g, node->x, depth) * max + (max - min);
		else n = count(g, node->x, depth) * (min + 1) + 2;
		if (n < 0 || n > REG_MAXPROG) die(g, "program too large");
		return n;
	case P_PAR: return count(g, node->x, depth) + 2;
	case P_PLA: return count(g, node->x, depth) + 2;
	case P_NLA: return count(g, node->x, depth) + 2;
	}
}


static Renode *parseatom(struct cstate *g)
{
	Renode *atom;
	if (g->lookahead == L_CHAR) {
		atom = newnode(g, P_CHAR);
		atom->c = g->yychar;
		next(g);
		return atom;
	}
	if (g->lookahead == L_CCLASS) {
		atom = newnode(g, P_CCLASS);
		atom->cc = g->yycc;
		next(g);
		return atom;
	}
	if (g->lookahead == L_NCCLASS) {
		atom = newnode(g, P_NCCLASS);
		atom->cc = g->yycc;
		next(g);
		return atom;
	}
	if (g->lookahead == L_REF) {
		atom = newnode(g, P_REF);
		if (g->yychar == 0 || g->yychar >= g->nsub || !g->sub[g->yychar])
			die(g, "invalid back-reference");
		atom->n = g->yychar;
		atom->x = g->sub[g->yychar];
		next(g);
		return atom;
	}
	if (accept(g, '.'))
		return newnode(g, P_ANY);
	if (accept(g, '(')) {
		atom = newnode(g, P_PAR);
		if (g->nsub == REG_MAXSUB)
			die(g, "too many captures");
		atom->n = g->nsub++;
		atom->x = parsealt(g);
		g->sub[atom->n] = atom;
		if (!accept(g, ')'))
			die(g, "unmatched '('");
		return atom;
	}
	if (accept(g, L_NC)) {
		atom = parsealt(g);
		if (!accept(g, ')'))
			die(g, "unmatched '('");
		return atom;
	}
	if (accept(g, L_PLA)) {
		atom = newnode(g, P_PLA);
		atom->x = parsealt(g);
		if (!accept(g, ')'))
			die(g, "unmatched '('");
		return atom;
	}
	if (accept(g, L_NLA)) {
		atom = newnode(g, P_NLA);
		atom->x = parsealt(g);
		if (!accept(g, ')'))
			die(g, "unmatched '('");
		return atom;
	}
	die(g, "syntax error");
	return NULL;
}


static int isnewline(int c)
{
	return c == 0xA || c == 0xD || c == 0x2028 || c == 0x2029;
}


static void pstmlist(int d, js_Ast *list)
{
	while (list) {
		assert(list->type == AST_LIST);
		pstm(d+1, list->a);
		nl();
		list = list->b;
	}
}


static void pvar(int d, js_Ast *var)
{
	assert(var->type == EXP_VAR);
	pexp(d, var->a);
	if (var->b) {
		sp(); pc('='); sp();
		pexp(d, var->b);
	}
}


GF_Err gf_media_export_webvtt_metadata(GF_MediaExporter *dumper)
{
	GF_ESD *esd;
	char szName[1000], szMedia[1000];
	FILE *med, *vtt;
	u32 w, h;
	u32 track, i, di, count, pos;
	u32 mtype, mstype;
	Bool isText;
	char *mime = NULL;
	Bool useBase64 = GF_FALSE;
	u32 headerLength = 0;

	if (!(track = gf_isom_get_track_by_id(dumper->file, dumper->trackID))) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("Wrong track ID %d for file %s \n", dumper->trackID, gf_isom_get_filename(dumper->file)));
		return GF_BAD_PARAM;
	}
	if (!track) return gf_export_message(dumper, GF_BAD_PARAM, "Invalid track ID %d", dumper->trackID);

	if (dumper->flags & GF_EXPORT_PROBE_ONLY) {
		return GF_OK;
	}
	esd = gf_isom_get_esd(dumper->file, track, 1);
	med = NULL;
	if (dumper->flags & GF_EXPORT_WEBVTT_META_EMBEDDED) {
	} else {
		sprintf(szMedia, "%s.media", dumper->out_name);
		med = gf_fopen(szMedia, "wb");
		if (!med) {
			if (esd) gf_odf_desc_del((GF_Descriptor *) esd);
			return gf_export_message(dumper, GF_IO_ERR, "Error opening %s for writing - check disk access & permissions", szMedia);
		}
	}

	sprintf(szName, "%s.vtt", dumper->out_name);
	vtt = gf_fopen(szName, "wt");
	if (!vtt) {
		gf_fclose(med);
		if (esd) gf_odf_desc_del((GF_Descriptor *) esd);
		return gf_export_message(dumper, GF_IO_ERR, "Error opening %s for writing - check disk access & permissions", szName);
	}

	mtype = gf_isom_get_media_type(dumper->file, track);
	if (mtype==GF_ISOM_MEDIA_TEXT || mtype == GF_ISOM_MEDIA_MPEG_SUBT || mtype == GF_ISOM_MEDIA_SUBT) {
		isText = GF_TRUE;
	} else {
		isText = GF_FALSE;
	}
	mstype = gf_isom_get_media_subtype(dumper->file, track, 1);

	/*write header*/
	gf_fprintf(vtt, "WEBVTT Metadata track generated by GPAC MP4Box %s\n", gf_sys_is_test_mode() ? "" : gf_gpac_version());

	gf_fprintf(vtt, "kind:metadata\n");
	{
		char *lang;
		gf_isom_get_media_language(dumper->file, track, &lang);
		gf_fprintf(vtt, "language:%s\n", lang);
		gf_free(lang);
	}
	{
		const char *handler;
		gf_isom_get_handler_name(dumper->file, track, &handler);
		gf_fprintf(vtt, "label: %s\n", handler);
	}
	if (gf_isom_is_track_in_root_od(dumper->file, track)) gf_fprintf(vtt, "inRootOD: yes\n");
	gf_fprintf(vtt, "trackID: %d\n", dumper->trackID);
	if (med) {
		gf_fprintf(vtt, "baseMediaFile: %s\n", gf_file_basename(szMedia));
	}
	if (esd) {
		/* TODO: export the MPEG-4 Stream type only if it is not a GPAC internal value */
		gf_fprintf(vtt, "MPEG-4-streamType: %d\n", esd->decoderConfig->streamType);
		/* TODO: export the MPEG-4 Object Type Indication only if it is not a GPAC internal value */
		gf_fprintf(vtt, "MPEG-4-objectTypeIndication: %d\n", esd->decoderConfig->objectTypeIndication);
		if (gf_isom_is_video_handler_type(mtype) ) {
			gf_isom_get_visual_info(dumper->file, track, 1, &w, &h);
			gf_fprintf(vtt, "width:%d\n", w);
			gf_fprintf(vtt, "height:%d\n", h);
		}
		else if (mtype==GF_ISOM_MEDIA_AUDIO) {
			u32 sr, nb_ch, bps;
			gf_isom_get_audio_info(dumper->file, track, 1, &sr, &nb_ch, &bps);
			gf_fprintf(vtt, "sampleRate: %d\n", sr);
			gf_fprintf(vtt, "numChannels: %d\n", nb_ch);
		} else if (isText) {
			s32 tx, ty;
			s16 layer;
			gf_isom_get_track_layout_info(dumper->file, track, &w, &h, &tx, &ty, &layer);
			gf_fprintf(vtt, "width:%d\n", w);
			gf_fprintf(vtt, "height:%d\n", h);
			if (tx || ty) gf_fprintf(vtt, "translation:%d,%d\n", tx, ty);
			if (layer) gf_fprintf(vtt, "layer:%d\n", layer);
		}
		if (esd->decoderConfig->decoderSpecificInfo  && esd->decoderConfig->decoderSpecificInfo->data) {
			if (isText) {
				if (mstype == GF_ISOM_SUBTYPE_WVTT) {
					/* Warning: Just use -raw export */
					mime = "text/vtt";
				} else if (mstype == GF_ISOM_SUBTYPE_STXT) {
					/* TODO: find the mime type from the ESD, assume SVG for now */
					mime = "image/svg+xml";
				} else if (mstype == GF_ISOM_SUBTYPE_STPP) {
					/* TODO: find the mime type from the ESD, assume TTML for now */
					mime = "application/ttml+xml";
				}
				if (dumper->flags & GF_EXPORT_WEBVTT_META_EMBEDDED) {
					if (mstype == GF_ISOM_SUBTYPE_STXT) {
						if (esd->decoderConfig->decoderSpecificInfo->dataLength) {
							gf_fprintf(vtt, "text-header: \n");
							gf_webvtt_dump_header_boxed(vtt, esd->decoderConfig->decoderSpecificInfo->data+4, esd->decoderConfig->decoderSpecificInfo->dataLength, &headerLength);
						}
					}
				} else {
					gf_webvtt_dump_header_boxed(med, esd->decoderConfig->decoderSpecificInfo->data+4, esd->decoderConfig->decoderSpecificInfo->dataLength, &headerLength);
					gf_fprintf(vtt, "text-header-length: %d\n", headerLength);
				}
			} else {
				char b64[200];
				u32 size = gf_base64_encode(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, b64, 200);
				useBase64 = GF_TRUE;
				if (size != (u32)-1 && size != 0) {
					b64[size] = 0;
					gf_fprintf(vtt, "MPEG-4-DecoderSpecificInfo: %s\n", b64);
				}
			}
		}
		gf_odf_desc_del((GF_Descriptor *) esd);
	} else {
		GF_GenericSampleDescription *sdesc = gf_isom_get_generic_sample_description(dumper->file, track, 1);
		gf_fprintf(vtt, "mediaType: %s\n", gf_4cc_to_str(mtype));
		gf_fprintf(vtt, "mediaSubType: %s\n", gf_4cc_to_str(mstype ));
		if (sdesc) {
			if (gf_isom_is_video_handler_type(mtype) ) {
				gf_fprintf(vtt, "codecVendor: %s\n", gf_4cc_to_str(sdesc->vendor_code));
				gf_fprintf(vtt, "codecVersion: %d\n", sdesc->version);
				gf_fprintf(vtt, "codecRevision: %d\n", sdesc->revision);
				gf_fprintf(vtt, "width: %d\n", sdesc->width);
				gf_fprintf(vtt, "height: %d\n", sdesc->height);
				gf_fprintf(vtt, "compressorName: %s\n", sdesc->compressor_name);
				gf_fprintf(vtt, "temporalQuality: %d\n", sdesc->temporal_quality);
				gf_fprintf(vtt, "spatialQuality: %d\n", sdesc->spatial_quality);
				gf_fprintf(vtt, "horizontalResolution: %d\n", sdesc->h_res);
				gf_fprintf(vtt, "verticalResolution: %d\n", sdesc->v_res);
				gf_fprintf(vtt, "bitDepth: %d\n", sdesc->depth);
			} else if (mtype==GF_ISOM_MEDIA_AUDIO) {
				gf_fprintf(vtt, "codecVendor: %s\n", gf_4cc_to_str(sdesc->vendor_code));
				gf_fprintf(vtt, "codecVersion: %d\n", sdesc->version);
				gf_fprintf(vtt, "codecRevision: %d\n", sdesc->revision);
				gf_fprintf(vtt, "sampleRate: %d\n", sdesc->samplerate);
				gf_fprintf(vtt, "numChannels: %d\n", sdesc->nb_channels);
				gf_fprintf(vtt, "bitsPerSample: %d\n", sdesc->bits_per_sample);
			}
			if (sdesc->extension_buf) {
				char b64[200];
				u32 size = gf_base64_encode(sdesc->extension_buf, sdesc->extension_buf_size, b64, 200);
				useBase64 = GF_TRUE;
				if (size != (u32)-1) {
					b64[size] = 0;
					gf_fprintf(vtt, "specificInfo: %s\n", b64);
					gf_free(sdesc->extension_buf);
				}
			}
			gf_free(sdesc);
		}
	}
	gf_fprintf(vtt, "inBandMetadataTrackDispatchType: %s\n", (mime ? mime : (isText? "text/plain" : "application/octet-stream")));
	if (useBase64) gf_fprintf(vtt, "encoding: base64\n");

	gf_fprintf(vtt, "\n");

	pos = 0;
	count = gf_isom_get_sample_count(dumper->file, track);
	for (i=0; i<count; i++) {
		GF_ISOSample *samp = gf_isom_get_sample(dumper->file, track, i+1, &di);
		if (!samp) break;

		{
			GF_WebVTTTimestamp start, end;
			u64 dur = gf_isom_get_sample_duration(dumper->file, track, i+1);
			gf_webvtt_timestamp_set(&start, samp->DTS);
			gf_webvtt_timestamp_set(&end, samp->DTS+dur);
			gf_webvtt_timestamp_dump(&start, vtt, GF_TRUE);
			gf_fprintf(vtt, " --> ");
			gf_webvtt_timestamp_dump(&end, vtt, GF_TRUE);
			gf_fprintf(vtt, " ");
			if (med) {
				gf_fprintf(vtt, "mediaOffset:%d ", pos+headerLength);
				gf_fprintf(vtt, "dataLength:%d ", samp->dataLength);
			}
			if (samp->CTS_Offset) gf_fprintf(vtt, "CTS: "LLD"", samp->DTS+samp->CTS_Offset);
			if (samp->IsRAP==RAP) gf_fprintf(vtt, "isRAP:true ");
			else if (samp->IsRAP==RAP_REDUNDANT) gf_fprintf(vtt, "isSyncShadow: true ");
			else gf_fprintf(vtt, "isRAP:false ");
			gf_fprintf(vtt, "\n");
		}
		if (med) {
			gf_fwrite(samp->data, samp->dataLength, med);
		} else if (dumper->flags & GF_EXPORT_WEBVTT_META_EMBEDDED) {
			if (isText) {
				samp->data = (char *)gf_realloc(samp->data, samp->dataLength+1);
				samp->data[samp->dataLength] = 0;
				gf_fprintf(vtt, "%s\n", samp->data);
			} else {
				u32 b64_size;
				char *b64;
				b64 = (char *)gf_malloc(samp->dataLength*3);
				b64_size = gf_base64_encode(samp->data, samp->dataLength, b64, samp->dataLength*3);
				if (b64_size != (u32)-1) {
					b64[b64_size] = 0;
					gf_fprintf(vtt, "%s\n", b64);
				}
				gf_free(b64);
			}
		}
		gf_fprintf(vtt, "\n");

		pos += samp->dataLength;
		gf_isom_sample_del(&samp);
		gf_set_progress("WebVTT metadata Export", i+1, count);
		if (dumper->flags & GF_EXPORT_DO_ABORT) break;
	}
	if (med) gf_fclose(med);
	gf_fclose(vtt);
	return GF_OK;
}