get_ofpact_map(enum ofp_version version)
{
    /* OpenFlow 1.0 actions. */
    static const struct ofpact_map of10[] = {
        { OFPACT_OUTPUT, 0 },
        { OFPACT_SET_VLAN_VID, 1 },
        { OFPACT_SET_VLAN_PCP, 2 },
        { OFPACT_STRIP_VLAN, 3 },
        { OFPACT_SET_ETH_SRC, 4 },
        { OFPACT_SET_ETH_DST, 5 },
        { OFPACT_SET_IPV4_SRC, 6 },
        { OFPACT_SET_IPV4_DST, 7 },
        { OFPACT_SET_IP_DSCP, 8 },
        { OFPACT_SET_L4_SRC_PORT, 9 },
        { OFPACT_SET_L4_DST_PORT, 10 },
        { OFPACT_ENQUEUE, 11 },
        { 0, -1 },
    };

    /* OpenFlow 1.1 actions. */
    static const struct ofpact_map of11[] = {
        { OFPACT_OUTPUT, 0 },
        { OFPACT_SET_VLAN_VID, 1 },
        { OFPACT_SET_VLAN_PCP, 2 },
        { OFPACT_SET_ETH_SRC, 3 },
        { OFPACT_SET_ETH_DST, 4 },
        { OFPACT_SET_IPV4_SRC, 5 },
        { OFPACT_SET_IPV4_DST, 6 },
        { OFPACT_SET_IP_DSCP, 7 },
        { OFPACT_SET_IP_ECN, 8 },
        { OFPACT_SET_L4_SRC_PORT, 9 },
        { OFPACT_SET_L4_DST_PORT, 10 },
        /* OFPAT_COPY_TTL_OUT (11) not supported. */
        /* OFPAT_COPY_TTL_IN (12) not supported. */
        { OFPACT_SET_MPLS_LABEL, 13 },
        { OFPACT_SET_MPLS_TC, 14 },
        { OFPACT_SET_MPLS_TTL, 15 },
        { OFPACT_DEC_MPLS_TTL, 16 },
        { OFPACT_PUSH_VLAN, 17 },
        { OFPACT_STRIP_VLAN, 18 },
        { OFPACT_PUSH_MPLS, 19 },
        { OFPACT_POP_MPLS, 20 },
        { OFPACT_SET_QUEUE, 21 },
        { OFPACT_GROUP, 22 },
        { OFPACT_SET_IP_TTL, 23 },
        { OFPACT_DEC_TTL, 24 },
        { 0, -1 },
    };

    /* OpenFlow 1.2, 1.3, and 1.4 actions. */
    static const struct ofpact_map of12[] = {
        { OFPACT_OUTPUT, 0 },
        /* OFPAT_COPY_TTL_OUT (11) not supported. */
        /* OFPAT_COPY_TTL_IN (12) not supported. */
        { OFPACT_SET_MPLS_TTL, 15 },
        { OFPACT_DEC_MPLS_TTL, 16 },
        { OFPACT_PUSH_VLAN, 17 },
        { OFPACT_STRIP_VLAN, 18 },
        { OFPACT_PUSH_MPLS, 19 },
        { OFPACT_POP_MPLS, 20 },
        { OFPACT_SET_QUEUE, 21 },
        { OFPACT_GROUP, 22 },
        { OFPACT_SET_IP_TTL, 23 },
        { OFPACT_DEC_TTL, 24 },
        { OFPACT_SET_FIELD, 25 },
        /* OF1.3+ OFPAT_PUSH_PBB (26) not supported. */
        /* OF1.3+ OFPAT_POP_PBB (27) not supported. */
        { 0, -1 },
    };

    switch (version) {
    case OFP10_VERSION:
        return of10;

    case OFP11_VERSION:
        return of11;

    case OFP12_VERSION:
    case OFP13_VERSION:
    case OFP14_VERSION:
    case OFP15_VERSION:
    case OFP16_VERSION:
    default:
        return of12;
    }
}


ofpact_decode_raw(enum ofp_version ofp_version,
                  const struct ofp_action_header *oah, size_t length,
                  const struct ofpact_raw_instance **instp)
{
    const struct ofpact_raw_instance *inst;
    struct ofpact_hdrs hdrs;

    *instp = NULL;
    if (length < sizeof *oah) {
        return OFPERR_OFPBAC_BAD_LEN;
    }

    /* Get base action type. */
    if (oah->type == htons(OFPAT_VENDOR)) {
        /* Get vendor. */
        hdrs.vendor = ntohl(oah->vendor);
        if (hdrs.vendor == NX_VENDOR_ID || hdrs.vendor == ONF_VENDOR_ID) {
            /* Get extension subtype. */
            const struct ext_action_header *nah;

            nah = ALIGNED_CAST(const struct ext_action_header *, oah);
            if (length < sizeof *nah) {
                return OFPERR_OFPBAC_BAD_LEN;
            }
            hdrs.type = ntohs(nah->subtype);
        } else {
            VLOG_WARN_RL(&rl, "OpenFlow action has unknown vendor %#"PRIx32,
                         hdrs.vendor);
            return OFPERR_OFPBAC_BAD_VENDOR;
        }
    } else {
        hdrs.vendor = 0;
        hdrs.type = ntohs(oah->type);
    }

    hdrs.ofp_version = ofp_version;
    HMAP_FOR_EACH_WITH_HASH (inst, decode_node, ofpact_hdrs_hash(&hdrs),
                             ofpact_decode_hmap()) {
        if (ofpact_hdrs_equal(&hdrs, &inst->hdrs)) {
            *instp = inst;
            return 0;
        }
    }

    return (hdrs.vendor
            ? OFPERR_OFPBAC_BAD_VENDOR_TYPE
            : OFPERR_OFPBAC_BAD_TYPE);
}


ofpact_check__(enum ofputil_protocol *usable_protocols, struct ofpact *a,
               struct flow *flow, ofp_port_t max_ports,
               uint8_t table_id, uint8_t n_tables)
{
    const struct ofpact_enqueue *enqueue;
    const struct mf_field *mf;

    switch (a->type) {
    case OFPACT_OUTPUT:
        return ofpact_check_output_port(ofpact_get_OUTPUT(a)->port,
                                        max_ports);

    case OFPACT_CONTROLLER:
        return 0;

    case OFPACT_ENQUEUE:
        enqueue = ofpact_get_ENQUEUE(a);
        if (ofp_to_u16(enqueue->port) >= ofp_to_u16(max_ports)
            && enqueue->port != OFPP_IN_PORT
            && enqueue->port != OFPP_LOCAL) {
            return OFPERR_OFPBAC_BAD_OUT_PORT;
        }
        return 0;

    case OFPACT_OUTPUT_REG:
        return mf_check_src(&ofpact_get_OUTPUT_REG(a)->src, flow);

    case OFPACT_OUTPUT_TRUNC:
        return ofpact_check_output_port(ofpact_get_OUTPUT_TRUNC(a)->port,
                                        max_ports);

    case OFPACT_BUNDLE:
        return bundle_check(ofpact_get_BUNDLE(a), max_ports, flow);

    case OFPACT_SET_VLAN_VID:
        /* Remember if we saw a vlan tag in the flow to aid translating to
         * OpenFlow 1.1+ if need be. */
        ofpact_get_SET_VLAN_VID(a)->flow_has_vlan =
            (flow->vlan_tci & htons(VLAN_CFI)) == htons(VLAN_CFI);
        if (!(flow->vlan_tci & htons(VLAN_CFI)) &&
            !ofpact_get_SET_VLAN_VID(a)->push_vlan_if_needed) {
            inconsistent_match(usable_protocols);
        }
        /* Temporary mark that we have a vlan tag. */
        flow->vlan_tci |= htons(VLAN_CFI);
        return 0;

    case OFPACT_SET_VLAN_PCP:
        /* Remember if we saw a vlan tag in the flow to aid translating to
         * OpenFlow 1.1+ if need be. */
        ofpact_get_SET_VLAN_PCP(a)->flow_has_vlan =
            (flow->vlan_tci & htons(VLAN_CFI)) == htons(VLAN_CFI);
        if (!(flow->vlan_tci & htons(VLAN_CFI)) &&
            !ofpact_get_SET_VLAN_PCP(a)->push_vlan_if_needed) {
            inconsistent_match(usable_protocols);
        }
        /* Temporary mark that we have a vlan tag. */
        flow->vlan_tci |= htons(VLAN_CFI);
        return 0;

    case OFPACT_STRIP_VLAN:
        if (!(flow->vlan_tci & htons(VLAN_CFI))) {
            inconsistent_match(usable_protocols);
        }
        /* Temporary mark that we have no vlan tag. */
        flow->vlan_tci = htons(0);
        return 0;

    case OFPACT_PUSH_VLAN:
        if (flow->vlan_tci & htons(VLAN_CFI)) {
            /* Multiple VLAN headers not supported. */
            return OFPERR_OFPBAC_BAD_TAG;
        }
        /* Temporary mark that we have a vlan tag. */
        flow->vlan_tci |= htons(VLAN_CFI);
        return 0;

    case OFPACT_SET_ETH_SRC:
    case OFPACT_SET_ETH_DST:
        return 0;

    case OFPACT_SET_IPV4_SRC:
    case OFPACT_SET_IPV4_DST:
        if (flow->dl_type != htons(ETH_TYPE_IP)) {
            inconsistent_match(usable_protocols);
        }
        return 0;

    case OFPACT_SET_IP_DSCP:
    case OFPACT_SET_IP_ECN:
    case OFPACT_SET_IP_TTL:
    case OFPACT_DEC_TTL:
        if (!is_ip_any(flow)) {
            inconsistent_match(usable_protocols);
        }
        return 0;

    case OFPACT_SET_L4_SRC_PORT:
    case OFPACT_SET_L4_DST_PORT:
        if (!is_ip_any(flow) || (flow->nw_frag & FLOW_NW_FRAG_LATER) ||
            (flow->nw_proto != IPPROTO_TCP && flow->nw_proto != IPPROTO_UDP
             && flow->nw_proto != IPPROTO_SCTP)) {
            inconsistent_match(usable_protocols);
        }
        /* Note on which transport protocol the port numbers are set.
         * This allows this set action to be converted to an OF1.2 set field
         * action. */
        if (a->type == OFPACT_SET_L4_SRC_PORT) {
            ofpact_get_SET_L4_SRC_PORT(a)->flow_ip_proto = flow->nw_proto;
        } else {
            ofpact_get_SET_L4_DST_PORT(a)->flow_ip_proto = flow->nw_proto;
        }
        return 0;

    case OFPACT_REG_MOVE:
        return nxm_reg_move_check(ofpact_get_REG_MOVE(a), flow);

    case OFPACT_SET_FIELD:
        mf = ofpact_get_SET_FIELD(a)->field;
        /* Require OXM_OF_VLAN_VID to have an existing VLAN header. */
        if (!mf_are_prereqs_ok(mf, flow, NULL) ||
            (mf->id == MFF_VLAN_VID && !(flow->vlan_tci & htons(VLAN_CFI)))) {
            VLOG_WARN_RL(&rl, "set_field %s lacks correct prerequisities",
                         mf->name);
            return OFPERR_OFPBAC_MATCH_INCONSISTENT;
        }
        /* Remember if we saw a vlan tag in the flow to aid translating to
         * OpenFlow 1.1 if need be. */
        ofpact_get_SET_FIELD(a)->flow_has_vlan =
            (flow->vlan_tci & htons(VLAN_CFI)) == htons(VLAN_CFI);
        if (mf->id == MFF_VLAN_TCI) {
            /* The set field may add or remove the vlan tag,
             * Mark the status temporarily. */
            flow->vlan_tci = ofpact_get_SET_FIELD(a)->value->be16;
        }
        return 0;

    case OFPACT_STACK_PUSH:
        return nxm_stack_push_check(ofpact_get_STACK_PUSH(a), flow);

    case OFPACT_STACK_POP:
        return nxm_stack_pop_check(ofpact_get_STACK_POP(a), flow);

    case OFPACT_SET_MPLS_LABEL:
    case OFPACT_SET_MPLS_TC:
    case OFPACT_SET_MPLS_TTL:
    case OFPACT_DEC_MPLS_TTL:
        if (!eth_type_mpls(flow->dl_type)) {
            inconsistent_match(usable_protocols);
        }
        return 0;

    case OFPACT_SET_TUNNEL:
    case OFPACT_SET_QUEUE:
    case OFPACT_POP_QUEUE:
    case OFPACT_RESUBMIT:
        return 0;

    case OFPACT_FIN_TIMEOUT:
        if (flow->nw_proto != IPPROTO_TCP) {
            inconsistent_match(usable_protocols);
        }
        return 0;

    case OFPACT_LEARN:
        return learn_check(ofpact_get_LEARN(a), flow);

    case OFPACT_CONJUNCTION:
        return 0;

    case OFPACT_MULTIPATH:
        return multipath_check(ofpact_get_MULTIPATH(a), flow);

    case OFPACT_NOTE:
    case OFPACT_EXIT:
        return 0;

    case OFPACT_PUSH_MPLS:
        flow->dl_type = ofpact_get_PUSH_MPLS(a)->ethertype;
        /* The packet is now MPLS and the MPLS payload is opaque.
         * Thus nothing can be assumed about the network protocol.
         * Temporarily mark that we have no nw_proto. */
        flow->nw_proto = 0;
        return 0;

    case OFPACT_POP_MPLS:
        if (!eth_type_mpls(flow->dl_type)) {
            inconsistent_match(usable_protocols);
        }
        flow->dl_type = ofpact_get_POP_MPLS(a)->ethertype;
        return 0;

    case OFPACT_SAMPLE:
        return 0;

    case OFPACT_CLONE: {
        struct ofpact_nest *on = ofpact_get_CLONE(a);
        return ofpacts_check(on->actions, ofpact_nest_get_action_len(on),
                             flow, max_ports, table_id, n_tables,
                             usable_protocols);
    }

    case OFPACT_CT: {
        struct ofpact_conntrack *oc = ofpact_get_CT(a);

        if (!dl_type_is_ip_any(flow->dl_type)
            || (flow->ct_state & CS_INVALID && oc->flags & NX_CT_F_COMMIT)
            || (oc->alg == IPPORT_FTP && flow->nw_proto != IPPROTO_TCP)
            || (oc->alg == IPPORT_TFTP && flow->nw_proto != IPPROTO_UDP)) {
            /* We can't downgrade to OF1.0 and expect inconsistent CT actions
             * be silently discarded.  Instead, datapath flow install fails, so
             * it is better to flag inconsistent CT actions as hard errors. */
            return OFPERR_OFPBAC_MATCH_INCONSISTENT;
        }

        if (oc->zone_src.field) {
            return mf_check_src(&oc->zone_src, flow);
        }

        return ofpacts_check(oc->actions, ofpact_ct_get_action_len(oc),
                             flow, max_ports, table_id, n_tables,
                             usable_protocols);
    }

    case OFPACT_CT_CLEAR:
        return 0;

    case OFPACT_NAT: {
        struct ofpact_nat *on = ofpact_get_NAT(a);

        if (!dl_type_is_ip_any(flow->dl_type) ||
            (on->range_af == AF_INET && flow->dl_type != htons(ETH_TYPE_IP)) ||
            (on->range_af == AF_INET6
             && flow->dl_type != htons(ETH_TYPE_IPV6))) {
            return OFPERR_OFPBAC_MATCH_INCONSISTENT;
        }
        return 0;
    }

    case OFPACT_CLEAR_ACTIONS:
        return 0;

    case OFPACT_WRITE_ACTIONS: {
        /* Use a temporary copy of 'usable_protocols' because we can't check
         * consistency of an action set. */
        struct ofpact_nest *on = ofpact_get_WRITE_ACTIONS(a);
        enum ofputil_protocol p = *usable_protocols;
        return ofpacts_check(on->actions, ofpact_nest_get_action_len(on),
                             flow, max_ports, table_id, n_tables, &p);
    }

    case OFPACT_WRITE_METADATA:
        return 0;

    case OFPACT_METER: {
        uint32_t mid = ofpact_get_METER(a)->meter_id;
        if (mid == 0 || mid > OFPM13_MAX) {
            return OFPERR_OFPMMFC_INVALID_METER;
        }
        return 0;
    }

    case OFPACT_GOTO_TABLE: {
        uint8_t goto_table = ofpact_get_GOTO_TABLE(a)->table_id;
        if ((table_id != 255 && goto_table <= table_id)
            || (n_tables != 255 && goto_table >= n_tables)) {
            return OFPERR_OFPBIC_BAD_TABLE_ID;
        }
        return 0;
    }

    case OFPACT_GROUP:
        return 0;

    case OFPACT_UNROLL_XLATE:
        /* UNROLL is an internal action that should never be seen via
         * OpenFlow. */
        return OFPERR_OFPBAC_BAD_TYPE;

    case OFPACT_DEBUG_RECIRC:
        return 0;

    default:
        OVS_NOT_REACHED();
    }
}


ovs_instruction_type_from_name(const char *name)
{
    const struct instruction_type_info *p;
    for (p = inst_info; p < &inst_info[ARRAY_SIZE(inst_info)]; p++) {
        if (!strcasecmp(name, p->name)) {
            return p->type;
        }
    }
    return -1;
}


ovs_instruction_type_from_ofpact_type(enum ofpact_type type)
{
    switch (type) {
    case OFPACT_METER:
        return OVSINST_OFPIT13_METER;
    case OFPACT_CLEAR_ACTIONS:
        return OVSINST_OFPIT11_CLEAR_ACTIONS;
    case OFPACT_WRITE_ACTIONS:
        return OVSINST_OFPIT11_WRITE_ACTIONS;
    case OFPACT_WRITE_METADATA:
        return OVSINST_OFPIT11_WRITE_METADATA;
    case OFPACT_GOTO_TABLE:
        return OVSINST_OFPIT11_GOTO_TABLE;
    case OFPACT_OUTPUT:
    case OFPACT_GROUP:
    case OFPACT_CLONE:
    case OFPACT_CONTROLLER:
    case OFPACT_ENQUEUE:
    case OFPACT_OUTPUT_REG:
    case OFPACT_OUTPUT_TRUNC:
    case OFPACT_BUNDLE:
    case OFPACT_SET_VLAN_VID:
    case OFPACT_SET_VLAN_PCP:
    case OFPACT_STRIP_VLAN:
    case OFPACT_PUSH_VLAN:
    case OFPACT_SET_ETH_SRC:
    case OFPACT_SET_ETH_DST:
    case OFPACT_SET_IPV4_SRC:
    case OFPACT_SET_IPV4_DST:
    case OFPACT_SET_IP_DSCP:
    case OFPACT_SET_IP_ECN:
    case OFPACT_SET_IP_TTL:
    case OFPACT_SET_L4_SRC_PORT:
    case OFPACT_SET_L4_DST_PORT:
    case OFPACT_REG_MOVE:
    case OFPACT_SET_FIELD:
    case OFPACT_STACK_PUSH:
    case OFPACT_STACK_POP:
    case OFPACT_DEC_TTL:
    case OFPACT_SET_MPLS_LABEL:
    case OFPACT_SET_MPLS_TC:
    case OFPACT_SET_MPLS_TTL:
    case OFPACT_DEC_MPLS_TTL:
    case OFPACT_PUSH_MPLS:
    case OFPACT_POP_MPLS:
    case OFPACT_SET_TUNNEL:
    case OFPACT_SET_QUEUE:
    case OFPACT_POP_QUEUE:
    case OFPACT_FIN_TIMEOUT:
    case OFPACT_RESUBMIT:
    case OFPACT_LEARN:
    case OFPACT_CONJUNCTION:
    case OFPACT_MULTIPATH:
    case OFPACT_NOTE:
    case OFPACT_EXIT:
    case OFPACT_UNROLL_XLATE:
    case OFPACT_SAMPLE:
    case OFPACT_DEBUG_RECIRC:
    case OFPACT_CT:
    case OFPACT_CT_CLEAR:
    case OFPACT_NAT:
    default:
        return OVSINST_OFPIT11_APPLY_ACTIONS;
    }
}


ofpact_put_reg_load(struct ofpbuf *ofpacts, const struct mf_field *field,
                    const void *value, const void *mask)
{
    struct ofpact_set_field *sf = ofpact_put_set_field(ofpacts, field, value,
                                                       mask);
    sf->ofpact.raw = NXAST_RAW_REG_LOAD;

    return sf;
}


parse_SET_VLAN_PCP(char *arg, struct ofpbuf *ofpacts,
                   enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
    return parse_set_vlan_pcp(arg, ofpacts, false);
}


decode_OFPAT_RAW11_SET_VLAN_PCP(uint8_t pcp,
                                enum ofp_version ofp_version OVS_UNUSED,
                                struct ofpbuf *out)
{
    return decode_set_vlan_pcp(pcp, false, out);
}


encode_SET_IPV4_DST(const struct ofpact_ipv4 *ipv4,
                    enum ofp_version ofp_version, struct ofpbuf *out)
{
    encode_SET_IPV4_addr(ipv4, ofp_version, OFPAT_RAW_SET_NW_DST, MFF_IPV4_DST,
                         out);
}


get_actions_from_instruction(const struct ofp11_instruction *inst,
                             const struct ofp_action_header **actions,
                             size_t *actions_len)
{
    *actions = ALIGNED_CAST(const struct ofp_action_header *, inst + 1);
    *actions_len = ntohs(inst->len) - sizeof *inst;
}


parse_METER(char *arg, struct ofpbuf *ofpacts,
            enum ofputil_protocol *usable_protocols)
{
    *usable_protocols &= OFPUTIL_P_OF13_UP;
    return str_to_u32(arg, &ofpact_put_METER(ofpacts)->meter_id);
}


get_ovsinst_map(enum ofp_version version)
{
    /* OpenFlow 1.1 and 1.2 instructions. */
    static const struct ovsinst_map of11[] = {
        { OVSINST_OFPIT11_GOTO_TABLE, 1 },
        { OVSINST_OFPIT11_WRITE_METADATA, 2 },
        { OVSINST_OFPIT11_WRITE_ACTIONS, 3 },
        { OVSINST_OFPIT11_APPLY_ACTIONS, 4 },
        { OVSINST_OFPIT11_CLEAR_ACTIONS, 5 },
        { 0, -1 },
    };

    /* OpenFlow 1.3+ instructions. */
    static const struct ovsinst_map of13[] = {
        { OVSINST_OFPIT11_GOTO_TABLE, 1 },
        { OVSINST_OFPIT11_WRITE_METADATA, 2 },
        { OVSINST_OFPIT11_WRITE_ACTIONS, 3 },
        { OVSINST_OFPIT11_APPLY_ACTIONS, 4 },
        { OVSINST_OFPIT11_CLEAR_ACTIONS, 5 },
        { OVSINST_OFPIT13_METER, 6 },
        { 0, -1 },
    };

    return version < OFP13_VERSION ? of11 : of13;
}


decode_NXAST_RAW_CONTROLLER2(const struct ext_action_header *eah,
                             enum ofp_version ofp_version OVS_UNUSED,
                             struct ofpbuf *out)
{
    if (!is_all_zeros(eah->pad, sizeof eah->pad)) {
        return OFPERR_NXBRC_MUST_BE_ZERO;
    }

    size_t start_ofs = out->size;
    struct ofpact_controller *oc = ofpact_put_CONTROLLER(out);
    oc->ofpact.raw = NXAST_RAW_CONTROLLER2;
    oc->max_len = UINT16_MAX;
    oc->reason = OFPR_ACTION;

    struct ofpbuf properties;
    ofpbuf_use_const(&properties, eah, ntohs(eah->len));
    ofpbuf_pull(&properties, sizeof *eah);

    while (properties.size > 0) {
        struct ofpbuf payload;
        uint64_t type;

        enum ofperr error = ofpprop_pull(&properties, &payload, &type);
        if (error) {
            return error;
        }

        switch (type) {
        case NXAC2PT_MAX_LEN:
            error = ofpprop_parse_u16(&payload, &oc->max_len);
            break;

        case NXAC2PT_CONTROLLER_ID:
            error = ofpprop_parse_u16(&payload, &oc->controller_id);
            break;

        case NXAC2PT_REASON: {
            uint8_t u8;
            error = ofpprop_parse_u8(&payload, &u8);
            oc->reason = u8;
            break;
        }

        case NXAC2PT_USERDATA:
            out->size = start_ofs + OFPACT_CONTROLLER_SIZE;
            ofpbuf_put(out, payload.msg, ofpbuf_msgsize(&payload));
            oc = ofpbuf_at_assert(out, start_ofs, sizeof *oc);
            oc->userdata_len = ofpbuf_msgsize(&payload);
            break;

        case NXAC2PT_PAUSE:
            oc->pause = true;
            break;

        default:
            error = OFPPROP_UNKNOWN(false, "NXAST_RAW_CONTROLLER2", type);
            break;
        }
        if (error) {
            return error;
        }
    }

    ofpact_finish_CONTROLLER(out, &oc);

    return 0;
}


set_field_to_nxast(const struct ofpact_set_field *sf, struct ofpbuf *openflow)
{
    /* If 'sf' cannot be encoded as NXAST_REG_LOAD because it requires an
     * experimenter OXM or is variable length (or if it came in as
     * NXAST_REG_LOAD2), encode as NXAST_REG_LOAD2.  Otherwise use
     * NXAST_REG_LOAD, which is backward compatible. */
    if (sf->ofpact.raw == NXAST_RAW_REG_LOAD2
        || !mf_nxm_header(sf->field->id) || sf->field->variable_len) {
        struct ext_action_header *eah OVS_UNUSED;
        size_t start_ofs = openflow->size;

        eah = put_NXAST_REG_LOAD2(openflow);
        openflow->size = openflow->size - sizeof eah->pad;
        nx_put_entry(openflow, sf->field, 0, sf->value,
                     ofpact_set_field_mask(sf));
        pad_ofpat(openflow, start_ofs);
    } else {
        struct mf_subfield dst;
        uint64_t value;

        dst.ofs = dst.n_bits = 0;
        while (next_load_segment(sf, &dst, &value)) {
            put_reg_load(openflow, &dst, value);
        }
    }
}


char **load_enc_file(char *enc_name)
{
    char buf[ENC_BUF_SIZE], *p, *r;
    int i, names_count;
    char **glyph_names;
    set_cur_file_name(enc_name);
    if (!enc_open()) {
        pdftex_fail("cannot open encoding file for reading");
    }
    glyph_names = xtalloc(256, char *);
    for (i = 0; i < 256; i++)
        glyph_names[i] = notdef;
    t1_log("{");
    t1_log(cur_file_name = (char *) nameoffile + 1);
    enc_getline();
    if (*enc_line != '/' || (r = strchr(enc_line, '[')) == NULL) {
        remove_eol(r, enc_line);
        pdftex_fail
           ("invalid encoding vector (a name or `[' missing): `%s'", enc_line);
    }
    names_count = 0;
    r++;                        /* skip '[' */
    skip(r, ' ');
    for (;;) {
        while (*r == '/') {
            for (p = buf, r++;
                 *r != ' ' && *r != 10 && *r != ']' && *r != '/'; *p++ = *r++);
            *p = 0;
            skip(r, ' ');
            if (names_count > 255)
                pdftex_fail("encoding vector contains more than 256 names");
            if (strcmp(buf, notdef) != 0)
                glyph_names[names_count] = xstrdup(buf);
            names_count++;
        }
        if (*r != 10 && *r != '%') {
            if (str_prefix(r, "] def"))
                goto done;
            else {
                remove_eol(r, enc_line);
                pdftex_fail
       ("invalid encoding vector: a name or `] def' expected: `%s'", enc_line);
            }
        }
        enc_getline();
        r = enc_line;
    }
  done:
    enc_close();
    t1_log("}");
    cur_file_name = NULL;
    return glyph_names;
}


static void t1_check_block_len(boolean decrypt)
{
    int l, c;
    if (t1_block_length == 0)
        return;
    c = t1_getbyte();
    if (decrypt)
        c = edecrypt((byte)c);
    l = t1_block_length;
    if (!(l == 0 && (c == 10 || c == 13))) {
        pdftex_warn("%i bytes more than expected were ignored", l + 1);
        while (l-- > 0)
            t1_getbyte();
    }
}


static int hexval(int c)
{
    if (c >= 'A' && c <= 'F')
        return c - 'A' + 10;
    else if (c >= 'a' && c <= 'f')
        return c - 'a' + 10;
    else if (c >= '0' && c <= '9')
        return c - '0';
    else
        return -1;
}


static void t1_start_eexec(void)
{
    int i;
    if (is_included(fm_cur)) {
        get_length1();
        save_offset();
    }
    if (!t1_pfa)
        t1_check_block_len(false);
    for (t1_line_ptr = t1_line_array, i = 0; i < 4; i++) {
        edecrypt((byte)t1_getbyte());
        *t1_line_ptr++ = 0;
    }
    t1_eexec_encrypt = true;
    if (is_included(fm_cur))
        t1_putline(); /* to put the first four bytes */
}


static void t1_read_subrs(void)
{
    int i, s;
    cs_entry *ptr;
    t1_getline();
    while (!(t1_charstrings() || t1_subrs())) {
        t1_scan_param();
        if (!t1_prefix("/UniqueID"))    /* ignore UniqueID for subsetted fonts */
            t1_putline();
        t1_getline();
    }
  found:
    t1_cs = true;
    t1_scan = false;
    if (!t1_subrs())
        return;
    subr_size_pos = strlen("/Subrs") + 1;
    /* subr_size_pos points to the number indicating dict size after "/Subrs" */
    subr_size = t1_scan_num(t1_line_array + subr_size_pos, 0);
    if (subr_size == 0) {
        while (!t1_charstrings())
            t1_getline();
        return;
    }
    subr_tab = xtalloc(subr_size, cs_entry);
    for (ptr = subr_tab; ptr - subr_tab < subr_size; ptr++)
        init_cs_entry(ptr);
    subr_array_start = xstrdup(t1_line_array);
    t1_getline();
    while (t1_cslen) {
        store_subr();
        t1_getline();
    }
    /* mark the first four entries without parsing */
    for (i = 0; i < subr_size && i < 4; i++)
        subr_tab[i].used = true;
    /* the end of the Subrs array might have more than one line so we need to
       concatnate them to subr_array_end. Unfortunately some fonts don't have
       the Subrs array followed by the CharStrings dict immediately (synthetic
       fonts). If we cannot find CharStrings in next POST_SUBRS_SCAN lines then
       we will treat the font as synthetic and ignore everything until next
       Subrs is found
     */

#define POST_SUBRS_SCAN  5

    s = 0;
    *t1_buf_array = 0;
    for (i = 0; i < POST_SUBRS_SCAN; i++) {
        if (t1_charstrings())
            break;
        s += t1_line_ptr - t1_line_array;
        alloc_array(t1_buf, s, T1_BUF_SIZE);
        strcat(t1_buf_array, t1_line_array);
        t1_getline();
    }
    subr_array_end = xstrdup(t1_buf_array);
    if (i == POST_SUBRS_SCAN) { /* CharStrings not found;
                                   suppose synthetic font */
        for (ptr = subr_tab; ptr - subr_tab < subr_size; ptr++)
            if (ptr->valid)
                xfree(ptr->data);
        xfree(subr_tab);
        xfree(subr_array_start);
        xfree(subr_array_end);
        cs_init();
        t1_cs = false;
        t1_synthetic = true;
        while (!(t1_charstrings() || t1_subrs()))
            t1_getline();
        goto found;
    }
}


static void cs_mark(const char *cs_name, int subr)
{
    byte *data;
    int i, b, cs_len;
    int last_cmd = 0;
    int a, a1, a2;
    unsigned short cr;
    /*tex The argument of last call to |OtherSubrs[3]|. */
    static int lastargOtherSubr3 = 3;
    cs_entry *ptr;
    cc_entry *cc;
    if (cs_name == NULL) {
        check_subr(subr);
        ptr = subr_tab + subr;
        if (!ptr->valid)
            return;
    } else if (cs_notdef != NULL && (cs_name == notdef || strcmp(cs_name, notdef) == 0)) {
        ptr = cs_notdef;
    }else {
        for (ptr = cs_tab; ptr < cs_ptr; ptr++)
            if (strcmp(ptr->name, cs_name) == 0)
                break;
        if (ptr == cs_ptr) {
            formatted_warning("type 1","glyph '%s' undefined", cs_name);
            return;
        }
        if (ptr->name == notdef)
            cs_notdef = ptr;
    }
    /*tex
        Only marked CharString entries and invalid entries can be skipped; valid
        marked subrs must be parsed to keep the stack in sync.
    */
    if (!ptr->valid || (ptr->used && cs_name != NULL))
        return;
    ptr->used = true;
    cr = 4330;
    cs_len = ptr->cslen;
    data = ptr->data + 4;
    for (i = 0; i < t1_lenIV; i++, cs_len--)
        cs_getchar();
    while (cs_len > 0) {
        --cs_len;
        b = cs_getchar();
        if (b >= 32) {
            if (b <= 246)
                a = b - 139;
            else if (b <= 250) {
                --cs_len;
                a = ((b - 247) << 8) + 108 + cs_getchar();
            } else if (b <= 254) {
                --cs_len;
                a = -((b - 251) << 8) - 108 - cs_getchar();
            } else {
                cs_len -= 4;
                a = (cs_getchar() & 0xff) << 24;
                a |= (cs_getchar() & 0xff) << 16;
                a |= (cs_getchar() & 0xff) << 8;
                a |= (cs_getchar() & 0xff) << 0;
                if (sizeof(int) > 4 && (a & 0x80000000))
                    a |= ~0x7FFFFFFF;
            }
            cc_push(a);
        } else {
            if (b == CS_ESCAPE) {
                b = cs_getchar() + CS_1BYTE_MAX;
                cs_len--;
            }
            if (b >= CS_MAX) {
                cs_fail(cs_name, subr, "command value out of range: %i", (int) b);
                goto cs_error;
            }
            cc = cc_tab + b;
            if (!cc->valid) {
                cs_fail(cs_name, subr, "command not valid: %i", (int) b);
                goto cs_error;
            }
            if (cc->bottom) {
                if (stack_ptr - cc_stack < cc->nargs)
                    cs_fail(cs_name, subr,
                            "less arguments on stack '%i' than required '%i'",
                            (int) (stack_ptr - cc_stack), (int) cc->nargs);
                else if (stack_ptr - cc_stack > cc->nargs)
                    cs_fail(cs_name, subr,
                            "more arguments on stack '%i' than required '%i'",
                            (int) (stack_ptr - cc_stack), (int) cc->nargs);
            }
            last_cmd = b;
            switch (cc - cc_tab) {
                case CS_CALLSUBR:
                    a1 = cc_get(-1);
                    cc_pop(1);
                    mark_subr(a1);
                    if (!subr_tab[a1].valid) {
                        cs_fail(cs_name, subr, "cannot call subr '%i'", (int) a1);
                        goto cs_error;
                    }
                    break;
                case CS_DIV:
                    cc_pop(2);
                    cc_push(0);
                    break;
                case CS_CALLOTHERSUBR:
                    if (cc_get(-1) == 3)
                        lastargOtherSubr3 = cc_get(-3);
                    a1 = cc_get(-2) + 2;
                    cc_pop(a1);
                    break;
                case CS_POP:
                    cc_push(lastargOtherSubr3);
                    /*tex
                        The only case when we care about the value being pushed
                        onto stack is when |POP| follows |CALLOTHERSUBR| changing
                        hints by |OtherSubrs[3]|.
                    */
                    break;
                case CS_SEAC:
                    a1 = cc_get(3);
                    a2 = cc_get(4);
                    cc_clear();
                    mark_cs(standard_glyph_names[a1]);
                    mark_cs(standard_glyph_names[a2]);
                    break;
                default:
                    if (cc->clear)
                        cc_clear();
            }
        }
    }
    if (cs_name == NULL && last_cmd != CS_RETURN) {
        formatted_warning("type 1",
            "last command in subr '%i' is not a RETURN; I will add it now but please consider fixing the font",
            (int) subr);
        append_cs_return(ptr);
    }
    return;
    /*tex An error occured during parsing: */
  cs_error:
    cc_clear();
    ptr->valid = false;
    ptr->used = false;
}


static boolean str_suffix(const char *begin_buf, const char *end_buf, const char *s)
{
    const char *s1 = end_buf - 1, *s2 = strend(s) - 1;
    if (*s1 == 10)
        s1--;
    while (s1 >= begin_buf && s2 >= s) {
        if (*s1-- != *s2--)
            return false;
    }
    return s2 < s;
}


static void t1_outhex(byte b)
{
    static const char *hexdigits = "0123456789ABCDEF";
    t1_putchar(hexdigits[b/16]);
    t1_putchar(hexdigits[b%16]);
    hexline_length += 2;
    end_hexline();
}


static void t1_start_eexec(PDF pdf)
{
    int i;
    get_length1();
    save_offset();
    if (!t1_pfa)
        t1_check_block_len(false);
    for (t1_line_ptr = t1_line_array, i = 0; i < 4; i++) {
        edecrypt((byte) t1_getbyte());
        *t1_line_ptr++ = 0;
    }
    t1_eexec_encrypt = true;
    /*tex To put the first four bytes: */
    t1_putline(pdf);
}


static void t1_check_block_len(boolean decrypt)
{
    int l, c;
    if (t1_block_length == 0)
        return;
    c = t1_getbyte();
    if (decrypt)
        c = edecrypt((byte)c);
    l = t1_block_length;
    if (!(l == 0 && (c == 10 || c == 13))) {
        pdftex_fail("%i bytes more than expected", l + 1);
    }
}


Try<JWT, JWTError> JWT::parse(const std::string& token)
{
  const vector<string> components = strings::split(token, ".");

  if (components.size() != 3) {
    return JWTError(
        "Expected 3 components in token, got " + stringify(components.size()),
        JWTError::Type::INVALID_TOKEN);
  }

  Try<JWT::Header> header = parse_header(components[0]);

  if (header.isError()) {
    return JWTError(header.error(), JWTError::Type::INVALID_TOKEN);
  }

  if (header->alg != JWT::Alg::None) {
    return JWTError(
        "Token 'alg' value \"" + stringify(header->alg) +
        "\" does not match, expected \"none\"",
        JWTError::Type::INVALID_TOKEN);
  }

  Try<JSON::Object> payload = parse_payload(components[1]);

  if (payload.isError()) {
    return JWTError(payload.error(), JWTError::Type::INVALID_TOKEN);
  }

  if (!components[2].empty()) {
    return JWTError(
        "Unsecured JWT contains a signature",
        JWTError::Type::INVALID_TOKEN);
  }

  return JWT(header.get(), payload.get(), None());
}


Try<JWT, JWTError> JWT::create(
    const JSON::Object& payload,
    const string& secret)
{
  const Header header{Alg::HS256, "JWT"};

  const Try<string> hmac = generate_hmac_sha256(
      base64::encode_url_safe(stringify(header), false) + "." +
        base64::encode_url_safe(stringify(payload), false),
      secret);

  if (hmac.isError()) {
    return JWTError(
        "Failed to generate HMAC signature: " + hmac.error(),
        JWTError::Type::UNKNOWN);
  }

  return JWT(header, payload, base64::encode_url_safe(hmac.get(), false));
}


insertEmphasisBegin(const EmphasisInfo *buffer, const int at,
		const EmphRuleNumber emphRule, const EmphasisClass class,
		const TranslationTableHeader *table, int pos, const InString *input,
		OutString *output, int *posMapping, int *cursorPosition, int *cursorStatus) {
	const TranslationTableRule *indicRule;
	if (buffer[at].begin & class) {
		if (brailleIndicatorDefined(
					table->emphRules[emphRule][begPhraseOffset], table, &indicRule))
			for_updatePositions(&indicRule->charsdots[0], 0, indicRule->dotslen, 0, pos,
					input, output, posMapping, cursorPosition, cursorStatus);
		else if (brailleIndicatorDefined(
						 table->emphRules[emphRule][begOffset], table, &indicRule))
			for_updatePositions(&indicRule->charsdots[0], 0, indicRule->dotslen, 0, pos,
					input, output, posMapping, cursorPosition, cursorStatus);
	}

	if (buffer[at].word & class
			// && !(buffer[at].begin & class)
			&& !(buffer[at].end & class)) {
		if (brailleIndicatorDefined(
					table->emphRules[emphRule][begWordOffset], table, &indicRule))
			for_updatePositions(&indicRule->charsdots[0], 0, indicRule->dotslen, 0, pos,
					input, output, posMapping, cursorPosition, cursorStatus);
	}
}


releaseStringBuffer(int idx) {
	if (idx >= 0 && idx < stringBufferPool->size) {
		int inUse = stringBufferPool->inUse[idx];
		if (inUse && stringBufferPool->free)
			stringBufferPool->free(stringBufferPool->buffers[idx]);
		stringBufferPool->inUse[idx] = 0;
		return inUse;
	}
	return 0;
}


removeGrouping(const InString **input, OutString *output, int passCharDots,
		int startReplace, TranslationTableRule *groupingRule, widechar groupingOp) {
	widechar startCharDots = groupingRule->charsdots[2 * passCharDots];
	widechar endCharDots = groupingRule->charsdots[2 * passCharDots + 1];
	int p;
	int level = 0;
	if (groupingOp == pass_groupstart) {
		for (p = startReplace + 1; p < (*input)->length; p++) {
			if ((*input)->chars[p] == startCharDots) level--;
			if ((*input)->chars[p] == endCharDots) level++;
			if (level == 1) break;
		}
		if (p == (*input)->length)
			return 0;
		else {
			// Create a new string instead of modifying it. This is slightly less
			// efficient, but makes the code more readable. Grouping is not a much used
			// feature anyway.
			int idx = getStringBuffer((*input)->length);
			widechar *chars = stringBufferPool->buffers[idx];
			int len = 0;
			int k;
			for (k = 0; k < (*input)->length; k++) {
				if (k == p) continue;
				chars[len++] = (*input)->chars[k];
			}
			*input = &(InString){.chars = chars, .length = len, .bufferIndex = idx };
		}
	} else {
		for (p = output->length - 1; p >= 0; p--) {
			if (output->chars[p] == endCharDots) level--;
			if (output->chars[p] == startCharDots) level++;
			if (level == 1) break;
		}
		if (p < 0) return 0;
		p++;
		for (; p < output->length; p++) output->chars[p - 1] = output->chars[p];
		output->length--;
	}
	return 1;
}


passDoTest(const TranslationTableHeader *table, int pos, const InString *input,
		int transOpcode, const TranslationTableRule *transRule, int *passCharDots,
		widechar const **passInstructions, int *passIC, PassRuleMatch *match,
		TranslationTableRule **groupingRule, widechar *groupingOp) {
	int searchIC, searchPos;
	int k;
	int not = 0;  // whether next operand should be reversed
	TranslationTableOffset ruleOffset = 0;
	TranslationTableRule *rule = NULL;
	TranslationTableCharacterAttributes attributes = 0;
	int startMatch = pos;
	int endMatch = pos;
	int startReplace = -1;
	int endReplace = -1;
	*groupingRule = NULL;
	*passInstructions = &transRule->charsdots[transRule->charslen];
	*passIC = 0;
	if (transOpcode == CTO_Context || transOpcode == CTO_Correct)
		*passCharDots = 0;
	else
		*passCharDots = 1;
	while (*passIC < transRule->dotslen) {
		int itsTrue = 1;  // whether we have a match or not
		if (pos > input->length) return 0;
		switch ((*passInstructions)[*passIC]) {
		case pass_first:
			if (pos != 0) itsTrue = 0;
			(*passIC)++;
			break;
		case pass_last:
			if (pos != input->length) itsTrue = 0;
			(*passIC)++;
			break;
		case pass_lookback:
			pos -= (*passInstructions)[*passIC + 1];
			if (pos < 0) {
				searchPos = 0;
				itsTrue = 0;
			}
			*passIC += 2;
			break;
		case pass_not:
			not = !not;
			(*passIC)++;
			continue;
		case pass_string:
		case pass_dots:
			itsTrue = matchCurrentInput(input, pos, *passInstructions, *passIC);
			pos += (*passInstructions)[*passIC + 1];
			*passIC += (*passInstructions)[*passIC + 1] + 2;
			break;
		case pass_startReplace:
			startReplace = pos;
			(*passIC)++;
			break;
		case pass_endReplace:
			endReplace = pos;
			(*passIC)++;
			break;
		case pass_attributes:
			attributes = ((*passInstructions)[*passIC + 1] << 16) |
					(*passInstructions)[*passIC + 2];
			for (k = 0; k < (*passInstructions)[*passIC + 3]; k++) {
				if (pos >= input->length) {
					itsTrue = 0;
					break;
				}
				if (input->chars[pos] == ENDSEGMENT) {
					itsTrue = 0;
					break;
				}
				if (!(findCharOrDots(input->chars[pos], *passCharDots,
							  table)->attributes &
							attributes)) {
					if (!not) {
						itsTrue = 0;
						break;
					}
				} else if (not) {
					itsTrue = 0;
					break;
				}
				pos++;
			}
			if (itsTrue) {
				for (k = (*passInstructions)[*passIC + 3];
						k < (*passInstructions)[*passIC + 4] && pos < input->length;
						k++) {
					if (input->chars[pos] == ENDSEGMENT) {
						itsTrue = 0;
						break;
					}
					if (!(findCharOrDots(input->chars[pos], *passCharDots,
								  table)->attributes &
								attributes)) {
						if (!not) break;
					} else if (not)
						break;
					pos++;
				}
			}
			not = 0;
			*passIC += 5;
			break;
		case pass_groupstart:
		case pass_groupend:
			ruleOffset = ((*passInstructions)[*passIC + 1] << 16) |
					(*passInstructions)[*passIC + 2];
			rule = (TranslationTableRule *)&table->ruleArea[ruleOffset];
			if (*passIC == 0 ||
					(*passIC > 0 &&
							(*passInstructions)[*passIC - 1] == pass_startReplace)) {
				*groupingRule = rule;
				*groupingOp = (*passInstructions)[*passIC];
			}
			if ((*passInstructions)[*passIC] == pass_groupstart)
				itsTrue =
						(input->chars[pos] == rule->charsdots[2 * *passCharDots]) ? 1 : 0;
			else
				itsTrue = (input->chars[pos] == rule->charsdots[2 * *passCharDots + 1])
						? 1
						: 0;
			pos++;
			*passIC += 3;
			break;
		case pass_swap:
			itsTrue = swapTest(*passIC, &pos, table, input, *passInstructions);
			*passIC += 5;
			break;
		case pass_search:
			itsTrue = doPassSearch(table, input, transRule, *passCharDots, pos,
					*passInstructions, *passIC, &searchIC, &searchPos, *groupingRule,
					*groupingOp);
			if ((!not&&!itsTrue) || (not&&itsTrue)) return 0;
			*passIC = searchIC;
			pos = searchPos;
		case pass_endTest:
			(*passIC)++;
			endMatch = pos;
			if (startReplace == -1) {
				startReplace = startMatch;
				endReplace = endMatch;
			}
			*match = (PassRuleMatch){.startMatch = startMatch,
				.startReplace = startReplace,
				.endReplace = endReplace,
				.endMatch = endMatch };
			return 1;
			break;
		default:
			if (_lou_handlePassVariableTest(*passInstructions, passIC, &itsTrue)) break;
			return 0;
		}
		if ((!not&&!itsTrue) || (not&&itsTrue)) return 0;
		not = 0;
	}
	return 0;
}


initEmphClasses() {
	EmphasisClass *classes = malloc(10 * sizeof(EmphasisClass));
	int j;
	if (!classes) _lou_outOfMemory();
	for (j = 0; j < 10; j++) {
		classes[j] = 0x1 << (j + 1);
	}
	emphClasses = classes;
}


swapReplace(int start, int end, const TranslationTableHeader *table,
		const InString *input, OutString *output, int *posMapping,
		const widechar *passInstructions, int passIC) {
	TranslationTableOffset swapRuleOffset;
	TranslationTableRule *swapRule;
	widechar *replacements;
	int p;
	swapRuleOffset = (passInstructions[passIC + 1] << 16) | passInstructions[passIC + 2];
	swapRule = (TranslationTableRule *)&table->ruleArea[swapRuleOffset];
	replacements = &swapRule->charsdots[swapRule->charslen];
	for (p = start; p < end; p++) {
		int rep;
		int test;
		int k;
		if (swapRule->opcode == CTO_SwapDd) {
			// A sequence of dot patterns is encoded as the length of the first dot
			// pattern (single widechar) followed by the contents of the first dot pattern
			// (one widechar per cell) followed by the length of the second dot pattern,
			// etc. See the function `compileSwapDots'. Because the third operand of a
			// swapdd rule can only contain single-cell dot patterns, the elements at
			// index 0, 2, ... are "1" and the elements at index 1, 3, ... are the dot
			// patterns.
			for (test = 0; test * 2 + 1 < swapRule->charslen; test++)
				if (input->chars[p] == swapRule->charsdots[test * 2 + 1]) break;
			if (test * 2 == swapRule->charslen) continue;
		} else {
			for (test = 0; test < swapRule->charslen; test++)
				if (input->chars[p] == swapRule->charsdots[test]) break;
			if (test == swapRule->charslen) continue;
		}
		k = 0;
		for (rep = 0; rep < test; rep++)
			if (swapRule->opcode == CTO_SwapCc)
				k++;
			else
				k += replacements[k];
		if (swapRule->opcode == CTO_SwapCc) {
			if ((output->length + 1) > output->maxlength) return 0;
			posMapping[output->length] = p;
			output->chars[output->length++] = replacements[k];
		} else {
			int l = replacements[k] - 1;
			int d = output->length + l;
			if (d > output->maxlength) return 0;
			while (--d >= output->length) posMapping[d] = p;
			memcpy(&output->chars[output->length], &replacements[k + 1],
					l * sizeof(*output->chars));
			output->length += l;
		}
	}
	return 1;
}


static void h2_session_ev_remote_goaway(h2_session *session, int arg, const char *msg)
{
    if (!session->remote.shutdown) {
        session->remote.error = arg;
        session->remote.accepting = 0;
        session->remote.shutdown = 1;
        cleanup_unprocessed_streams(session);
        update_child_status(session, SERVER_CLOSING, "remote goaway");
        transit(session, "remote goaway", H2_SESSION_ST_DONE);
    }
}


apr_status_t h2_session_create(h2_session **psession,
                               conn_rec *c, h2_ctx *ctx, h2_workers *workers)
{
    return h2_session_create_int(psession, c, NULL, ctx, workers);
}


static void h2_session_ev_stream_change(h2_session *session, int arg, const char *msg)
{
    switch (session->state) {
        case H2_SESSION_ST_IDLE:
        case H2_SESSION_ST_WAIT:
            transit(session, "stream change", H2_SESSION_ST_BUSY);
            break;
        default:
            /* nop */
            break;
    }
}


static int on_invalid_header_cb(nghttp2_session *ngh2,
                                const nghttp2_frame *frame,
                                const uint8_t *name, size_t namelen,
                                const uint8_t *value, size_t valuelen,
                                uint8_t flags, void *user_data)
{
    h2_session *session = user_data;
    h2_stream *stream;

    if (APLOGcdebug(session->c)) {
        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c, APLOGNO(03456)
                      "h2_stream(%ld-%d): invalid header '%s: %s'",
                      session->id, (int)frame->hd.stream_id,
                      apr_pstrndup(session->pool, (const char *)name, namelen),
                      apr_pstrndup(session->pool, (const char *)value, valuelen));
    }
    stream = h2_session_stream_get(session, frame->hd.stream_id);
    if (stream) {
        h2_stream_rst(stream, NGHTTP2_PROTOCOL_ERROR);
    }
    return 0;
}


static apr_status_t session_read(h2_session *session, apr_size_t readlen, int block)
{
    apr_status_t status, rstatus = APR_EAGAIN;
    conn_rec *c = session->c;
    apr_off_t read_start = session->io.bytes_read;

    while (1) {
        /* H2_IN filter handles all incoming data against the session.
         * We just pull at the filter chain to make it happen */
        status = ap_get_brigade(c->input_filters,
                                session->bbtmp, AP_MODE_READBYTES,
                                block? APR_BLOCK_READ : APR_NONBLOCK_READ,
                                H2MAX(APR_BUCKET_BUFF_SIZE, readlen));
        /* get rid of any possible data we do not expect to get */
        apr_brigade_cleanup(session->bbtmp);

        switch (status) {
            case APR_SUCCESS:
                /* successful read, reset our idle timers */
                rstatus = APR_SUCCESS;
                if (block) {
                    /* successful blocked read, try unblocked to
                     * get more. */
                    block = 0;
                }
                break;
            case APR_EAGAIN:
                return rstatus;
            case APR_TIMEUP:
                return status;
            default:
                if (session->io.bytes_read == read_start) {
                    /* first attempt failed */
                    if (APR_STATUS_IS_ETIMEDOUT(status)
                        || APR_STATUS_IS_ECONNABORTED(status)
                        || APR_STATUS_IS_ECONNRESET(status)
                        || APR_STATUS_IS_EOF(status)
                        || APR_STATUS_IS_EBADF(status)) {
                        /* common status for a client that has left */
                        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, c,
                                      H2_SSSN_MSG(session, "input gone"));
                    }
                    else {
                        /* uncommon status, log on INFO so that we see this */
                        ap_log_cerror( APLOG_MARK, APLOG_DEBUG, status, c,
                                      H2_SSSN_LOG(APLOGNO(02950), session,
                                      "error reading, terminating"));
                    }
                    return status;
                }
                /* subsequent failure after success(es), return initial
                 * status. */
                return rstatus;
        }
        if ((session->io.bytes_read - read_start) > readlen) {
            /* read enough in one go, give write a chance */
            ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, c,
                          H2_SSSN_MSG(session, "read enough, returning"));
            break;
        }
    }
    return rstatus;
}


static void h2_session_ev_conn_error(h2_session *session, int arg, const char *msg)
{
    switch (session->state) {
        case H2_SESSION_ST_INIT:
        case H2_SESSION_ST_DONE:
            /* just leave */
            transit(session, "conn error", H2_SESSION_ST_DONE);
            break;

        default:
            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, session->c,
                          H2_SSSN_LOG(APLOGNO(03401), session,
                          "conn error -> shutdown"));
            h2_session_shutdown(session, arg, msg, 0);
            break;
    }
}


static void h2_session_ev_conn_timeout(h2_session *session, int arg, const char *msg)
{
    transit(session, msg, H2_SESSION_ST_DONE);
    if (!session->local.shutdown) {
        h2_session_shutdown(session, arg, msg, 1);
    }
}


const char *h2_session_state_str(h2_session_state state)
{
    if (state >= (sizeof(StateNames)/sizeof(StateNames[0]))) {
        return "unknown";
    }
    return StateNames[state];
}


static apr_status_t session_pool_cleanup(void *data)
{
    conn_rec *c = data;
    h2_session *session;
    h2_ctx *ctx = h2_ctx_get(c, 0);

    if (ctx && (session = h2_ctx_session_get(ctx))) {
        /* if the session is still there, now is the last chance
         * to perform cleanup. Normally, cleanup should have happened
         * earlier in the connection pre_close. Main reason is that
         * any ongoing requests on slave connections might still access
         * data which has, at this time, already been freed. An example
         * is mod_ssl that uses request hooks. */
        ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c,
                      H2_SSSN_LOG(APLOGNO(10020), session,
                      "session cleanup triggered by pool cleanup. "
                      "this should have happened earlier already."));
        return session_cleanup(session, "pool cleanup");
    }
    return APR_SUCCESS;
}


    void CrwMap::encode0x2008(const Image&      image,
                              const CrwMapping* pCrwMapping,
                                    CiffHeader* pHead)
    {
        assert(pCrwMapping != 0);
        assert(pHead != 0);

        ExifThumbC exifThumb(image.exifData());
        DataBuf buf = exifThumb.copy();
        if (buf.size_ != 0) {
            pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf);
        }
        else {
            pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_);
        }
    } // CrwMap::encode0x2008


    void CrwMap::encode0x180e(const Image&      image,
                              const CrwMapping* pCrwMapping,
                                    CiffHeader* pHead)
    {
        assert(pCrwMapping != 0);
        assert(pHead != 0);

        time_t t = 0;
        const ExifKey key(pCrwMapping->tag_, Internal::groupName(pCrwMapping->ifdId_));
        const ExifData::const_iterator ed = image.exifData().findKey(key);
        if (ed != image.exifData().end()) {
            struct tm tm;
            std::memset(&tm, 0x0, sizeof(tm));
            int rc = exifTime(ed->toString().c_str(), &tm);
            if (rc == 0) t = timegm(&tm);
        }
        if (t != 0) {
            DataBuf buf(12);
            std::memset(buf.pData_, 0x0, 12);
            ul2Data(buf.pData_, static_cast<uint32_t>(t), pHead->byteOrder());
            pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf);
        }
        else {
            pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_);
        }
    } // CrwMap::encode0x180e


    void CrwMap::decode0x2008(const CiffComponent& ciffComponent,
                              const CrwMapping*    /*pCrwMapping*/,
                                    Image&         image,
                                    ByteOrder      /*byteOrder*/)
    {
        ExifThumb exifThumb(image.exifData());
        exifThumb.setJpegThumbnail(ciffComponent.pData(), ciffComponent.size());
    } // CrwMap::decode0x2008


    CiffDirectory::~CiffDirectory()
    {
        Components::iterator b = components_.begin();
        Components::iterator e = components_.end();
        for (Components::iterator i = b; i != e; ++i) {
            delete *i;
        }
    }


    void CiffHeader::read(const byte* pData, uint32_t size)
    {
        if (size < 14) throw Error(kerNotACrwImage);

        if (pData[0] == 'I' && pData[0] == pData[1]) {
            byteOrder_ = littleEndian;
        }
        else if (pData[0] == 'M' && pData[0] == pData[1]) {
            byteOrder_ = bigEndian;
        }
        else {
            throw Error(kerNotACrwImage);
        }
        offset_ = getULong(pData + 2, byteOrder_);
        if (offset_ < 14 || offset_ > size) throw Error(kerNotACrwImage);
        if (std::memcmp(pData + 6, signature(), 8) != 0) {
            throw Error(kerNotACrwImage);
        }

        delete pPadding_;
        pPadding_ = new byte[offset_ - 14];
        padded_ = offset_ - 14;
        std::memcpy(pPadding_, pData + 14, padded_);

        pRootDir_ = new CiffDirectory;
        pRootDir_->readDirectory(pData + offset_, size - offset_, byteOrder_);
    } // CiffHeader::read


    void CiffHeader::print(std::ostream& os, const std::string& prefix) const
    {
        std::ios::fmtflags f( os.flags() );
        os << prefix
           << _("Header, offset") << " = 0x" << std::setw(8) << std::setfill('0')
           << std::hex << std::right << offset_ << "\n";
        if (pRootDir_) pRootDir_->print(os, byteOrder_, prefix);
        os.flags(f);
    } // CiffHeader::print


static u64 core_reg_offset_from_id(u64 id)
{
	return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE);
}


int kvm_arm_vcpu_arch_set_attr(struct kvm_vcpu *vcpu,
			       struct kvm_device_attr *attr)
{
	int ret;

	switch (attr->group) {
	case KVM_ARM_VCPU_PMU_V3_CTRL:
		ret = kvm_arm_pmu_v3_set_attr(vcpu, attr);
		break;
	case KVM_ARM_VCPU_TIMER_CTRL:
		ret = kvm_arm_timer_set_attr(vcpu, attr);
		break;
	default:
		ret = -ENXIO;
		break;
	}

	return ret;
}


int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
{
	/* We currently use nothing arch-specific in upper 32 bits */
	if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
		return -EINVAL;

	/* Register group 16 means we want a core register. */
	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
		return get_core_reg(vcpu, reg);

	if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_FW)
		return kvm_arm_get_fw_reg(vcpu, reg);

	if (is_timer_reg(reg->id))
		return get_timer_reg(vcpu, reg);

	return kvm_arm_sys_reg_get_reg(vcpu, reg);
}


int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
				  struct kvm_sregs *sregs)
{
	return -EINVAL;
}


scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n)
{
  int s;
  size_t extra_zeroes;
  unsigned int abs_n;
  unsigned int abs_s;
  mp_limb_t *pow5_ptr;
  size_t pow5_len;
  unsigned int s_limbs;
  unsigned int s_bits;
  mpn_t pow5;
  mpn_t z;
  void *z_memory;
  char *digits;

  if (memory == NULL)
    return NULL;
  /* x = 2^e * m, hence
     y = round (2^e * 10^n * m) = round (2^(e+n) * 5^n * m)
       = round (2^s * 5^n * m).  */
  s = e + n;
  extra_zeroes = 0;
  /* Factor out a common power of 10 if possible.  */
  if (s > 0 && n > 0)
    {
      extra_zeroes = (s < n ? s : n);
      s -= extra_zeroes;
      n -= extra_zeroes;
    }
  /* Here y = round (2^s * 5^n * m) * 10^extra_zeroes.
     Before converting to decimal, we need to compute
     z = round (2^s * 5^n * m).  */
  /* Compute 5^|n|, possibly shifted by |s| bits if n and s have the same
     sign.  2.322 is slightly larger than log(5)/log(2).  */
  abs_n = (n >= 0 ? n : -n);
  abs_s = (s >= 0 ? s : -s);
  pow5_ptr = (mp_limb_t *) malloc (((int)(abs_n * (2.322f / GMP_LIMB_BITS)) + 1
                                    + abs_s / GMP_LIMB_BITS + 1)
                                   * sizeof (mp_limb_t));
  if (pow5_ptr == NULL)
    {
      free (memory);
      return NULL;
    }
  /* Initialize with 1.  */
  pow5_ptr[0] = 1;
  pow5_len = 1;
  /* Multiply with 5^|n|.  */
  if (abs_n > 0)
    {
      static mp_limb_t const small_pow5[13 + 1] =
        {
          1, 5, 25, 125, 625, 3125, 15625, 78125, 390625, 1953125, 9765625,
          48828125, 244140625, 1220703125
        };
      unsigned int n13;
      for (n13 = 0; n13 <= abs_n; n13 += 13)
        {
          mp_limb_t digit1 = small_pow5[n13 + 13 <= abs_n ? 13 : abs_n - n13];
          size_t j;
          mp_twolimb_t carry = 0;
          for (j = 0; j < pow5_len; j++)
            {
              mp_limb_t digit2 = pow5_ptr[j];
              carry += (mp_twolimb_t) digit1 * (mp_twolimb_t) digit2;
              pow5_ptr[j] = (mp_limb_t) carry;
              carry = carry >> GMP_LIMB_BITS;
            }
          if (carry > 0)
            pow5_ptr[pow5_len++] = (mp_limb_t) carry;
        }
    }
  s_limbs = abs_s / GMP_LIMB_BITS;
  s_bits = abs_s % GMP_LIMB_BITS;
  if (n >= 0 ? s >= 0 : s <= 0)
    {
      /* Multiply with 2^|s|.  */
      if (s_bits > 0)
        {
          mp_limb_t *ptr = pow5_ptr;
          mp_twolimb_t accu = 0;
          size_t count;
          for (count = pow5_len; count > 0; count--)
            {
              accu += (mp_twolimb_t) *ptr << s_bits;
              *ptr++ = (mp_limb_t) accu;
              accu = accu >> GMP_LIMB_BITS;
            }
          if (accu > 0)
            {
              *ptr = (mp_limb_t) accu;
              pow5_len++;
            }
        }
      if (s_limbs > 0)
        {
          size_t count;
          for (count = pow5_len; count > 0;)
            {
              count--;
              pow5_ptr[s_limbs + count] = pow5_ptr[count];
            }
          for (count = s_limbs; count > 0;)
            {
              count--;
              pow5_ptr[count] = 0;
            }
          pow5_len += s_limbs;
        }
      pow5.limbs = pow5_ptr;
      pow5.nlimbs = pow5_len;
      if (n >= 0)
        {
          /* Multiply m with pow5.  No division needed.  */
          z_memory = multiply (m, pow5, &z);
        }
      else
        {
          /* Divide m by pow5 and round.  */
          z_memory = divide (m, pow5, &z);
        }
    }
  else
    {
      pow5.limbs = pow5_ptr;
      pow5.nlimbs = pow5_len;
      if (n >= 0)
        {
          /* n >= 0, s < 0.
             Multiply m with pow5, then divide by 2^|s|.  */
          mpn_t numerator;
          mpn_t denominator;
          void *tmp_memory;
          tmp_memory = multiply (m, pow5, &numerator);
          if (tmp_memory == NULL)
            {
              free (pow5_ptr);
              free (memory);
              return NULL;
            }
          /* Construct 2^|s|.  */
          {
            mp_limb_t *ptr = pow5_ptr + pow5_len;
            size_t i;
            for (i = 0; i < s_limbs; i++)
              ptr[i] = 0;
            ptr[s_limbs] = (mp_limb_t) 1 << s_bits;
            denominator.limbs = ptr;
            denominator.nlimbs = s_limbs + 1;
          }
          z_memory = divide (numerator, denominator, &z);
          free (tmp_memory);
        }
      else
        {
          /* n < 0, s > 0.
             Multiply m with 2^s, then divide by pow5.  */
          mpn_t numerator;
          mp_limb_t *num_ptr;
          num_ptr = (mp_limb_t *) malloc ((m.nlimbs + s_limbs + 1)
                                          * sizeof (mp_limb_t));
          if (num_ptr == NULL)
            {
              free (pow5_ptr);
              free (memory);
              return NULL;
            }
          {
            mp_limb_t *destptr = num_ptr;
            {
              size_t i;
              for (i = 0; i < s_limbs; i++)
                *destptr++ = 0;
            }
            if (s_bits > 0)
              {
                const mp_limb_t *sourceptr = m.limbs;
                mp_twolimb_t accu = 0;
                size_t count;
                for (count = m.nlimbs; count > 0; count--)
                  {
                    accu += (mp_twolimb_t) *sourceptr++ << s_bits;
                    *destptr++ = (mp_limb_t) accu;
                    accu = accu >> GMP_LIMB_BITS;
                  }
                if (accu > 0)
                  *destptr++ = (mp_limb_t) accu;
              }
            else
              {
                const mp_limb_t *sourceptr = m.limbs;
                size_t count;
                for (count = m.nlimbs; count > 0; count--)
                  *destptr++ = *sourceptr++;
              }
            numerator.limbs = num_ptr;
            numerator.nlimbs = destptr - num_ptr;
          }
          z_memory = divide (numerator, pow5, &z);
          free (num_ptr);
        }
    }
  free (pow5_ptr);
  free (memory);

  /* Here y = round (x * 10^n) = z * 10^extra_zeroes.  */

  if (z_memory == NULL)
    return NULL;
  digits = convert_to_decimal (z, extra_zeroes);
  free (z_memory);
  return digits;
}


divide (mpn_t a, mpn_t b, mpn_t *q)
{
  /* Algorithm:
     First normalise a and b: a=[a[m-1],...,a[0]], b=[b[n-1],...,b[0]]
     with m>=0 and n>0 (in base beta = 2^GMP_LIMB_BITS).
     If m<n, then q:=0 and r:=a.
     If m>=n=1, perform a single-precision division:
       r:=0, j:=m,
       while j>0 do
         {Here (q[m-1]*beta^(m-1)+...+q[j]*beta^j) * b[0] + r*beta^j =
               = a[m-1]*beta^(m-1)+...+a[j]*beta^j und 0<=r<b[0]<beta}
         j:=j-1, r:=r*beta+a[j], q[j]:=floor(r/b[0]), r:=r-b[0]*q[j].
       Normalise [q[m-1],...,q[0]], yields q.
     If m>=n>1, perform a multiple-precision division:
       We have a/b < beta^(m-n+1).
       s:=intDsize-1-(highest bit in b[n-1]), 0<=s<intDsize.
       Shift a and b left by s bits, copying them. r:=a.
       r=[r[m],...,r[0]], b=[b[n-1],...,b[0]] with b[n-1]>=beta/2.
       For j=m-n,...,0: {Here 0 <= r < b*beta^(j+1).}
         Compute q* :
           q* := floor((r[j+n]*beta+r[j+n-1])/b[n-1]).
           In case of overflow (q* >= beta) set q* := beta-1.
           Compute c2 := ((r[j+n]*beta+r[j+n-1]) - q* * b[n-1])*beta + r[j+n-2]
           and c3 := b[n-2] * q*.
           {We have 0 <= c2 < 2*beta^2, even 0 <= c2 < beta^2 if no overflow
            occurred.  Furthermore 0 <= c3 < beta^2.
            If there was overflow and
            r[j+n]*beta+r[j+n-1] - q* * b[n-1] >= beta, i.e. c2 >= beta^2,
            the next test can be skipped.}
           While c3 > c2, {Here 0 <= c2 < c3 < beta^2}
             Put q* := q* - 1, c2 := c2 + b[n-1]*beta, c3 := c3 - b[n-2].
           If q* > 0:
             Put r := r - b * q* * beta^j. In detail:
               [r[n+j],...,r[j]] := [r[n+j],...,r[j]] - q* * [b[n-1],...,b[0]].
               hence: u:=0, for i:=0 to n-1 do
                              u := u + q* * b[i],
                              r[j+i]:=r[j+i]-(u mod beta) (+ beta, if carry),
                              u:=u div beta (+ 1, if carry in subtraction)
                      r[n+j]:=r[n+j]-u.
               {Since always u = (q* * [b[i-1],...,b[0]] div beta^i) + 1
                               < q* + 1 <= beta,
                the carry u does not overflow.}
             If a negative carry occurs, put q* := q* - 1
               and [r[n+j],...,r[j]] := [r[n+j],...,r[j]] + [0,b[n-1],...,b[0]].
         Set q[j] := q*.
       Normalise [q[m-n],..,q[0]]; this yields the quotient q.
       Shift [r[n-1],...,r[0]] right by s bits and normalise; this yields the
       rest r.
       The room for q[j] can be allocated at the memory location of r[n+j].
     Finally, round-to-even:
       Shift r left by 1 bit.
       If r > b or if r = b and q[0] is odd, q := q+1.
   */
  const mp_limb_t *a_ptr = a.limbs;
  size_t a_len = a.nlimbs;
  const mp_limb_t *b_ptr = b.limbs;
  size_t b_len = b.nlimbs;
  mp_limb_t *roomptr;
  mp_limb_t *tmp_roomptr = NULL;
  mp_limb_t *q_ptr;
  size_t q_len;
  mp_limb_t *r_ptr;
  size_t r_len;

  /* Allocate room for a_len+2 digits.
     (Need a_len+1 digits for the real division and 1 more digit for the
     final rounding of q.)  */
  roomptr = (mp_limb_t *) malloc ((a_len + 2) * sizeof (mp_limb_t));
  if (roomptr == NULL)
    return NULL;

  /* Normalise a.  */
  while (a_len > 0 && a_ptr[a_len - 1] == 0)
    a_len--;

  /* Normalise b.  */
  for (;;)
    {
      if (b_len == 0)
        /* Division by zero.  */
        abort ();
      if (b_ptr[b_len - 1] == 0)
        b_len--;
      else
        break;
    }

  /* Here m = a_len >= 0 and n = b_len > 0.  */

  if (a_len < b_len)
    {
      /* m<n: trivial case.  q=0, r := copy of a.  */
      r_ptr = roomptr;
      r_len = a_len;
      memcpy (r_ptr, a_ptr, a_len * sizeof (mp_limb_t));
      q_ptr = roomptr + a_len;
      q_len = 0;
    }
  else if (b_len == 1)
    {
      /* n=1: single precision division.
         beta^(m-1) <= a < beta^m  ==>  beta^(m-2) <= a/b < beta^m  */
      r_ptr = roomptr;
      q_ptr = roomptr + 1;
      {
        mp_limb_t den = b_ptr[0];
        mp_limb_t remainder = 0;
        const mp_limb_t *sourceptr = a_ptr + a_len;
        mp_limb_t *destptr = q_ptr + a_len;
        size_t count;
        for (count = a_len; count > 0; count--)
          {
            mp_twolimb_t num =
              ((mp_twolimb_t) remainder << GMP_LIMB_BITS) | *--sourceptr;
            *--destptr = num / den;
            remainder = num % den;
          }
        /* Normalise and store r.  */
        if (remainder > 0)
          {
            r_ptr[0] = remainder;
            r_len = 1;
          }
        else
          r_len = 0;
        /* Normalise q.  */
        q_len = a_len;
        if (q_ptr[q_len - 1] == 0)
          q_len--;
      }
    }
  else
    {
      /* n>1: multiple precision division.
         beta^(m-1) <= a < beta^m, beta^(n-1) <= b < beta^n  ==>
         beta^(m-n-1) <= a/b < beta^(m-n+1).  */
      /* Determine s.  */
      size_t s;
      {
        mp_limb_t msd = b_ptr[b_len - 1]; /* = b[n-1], > 0 */
        /* Determine s = GMP_LIMB_BITS - integer_length (msd).
           Code copied from gnulib's integer_length.c.  */
# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
        s = __builtin_clz (msd);
# else
#  if defined DBL_EXPBIT0_WORD && defined DBL_EXPBIT0_BIT
        if (GMP_LIMB_BITS <= DBL_MANT_BIT)
          {
            /* Use 'double' operations.
               Assumes an IEEE 754 'double' implementation.  */
#   define DBL_EXP_MASK ((DBL_MAX_EXP - DBL_MIN_EXP) | 7)
#   define DBL_EXP_BIAS (DBL_EXP_MASK / 2 - 1)
#   define NWORDS \
     ((sizeof (double) + sizeof (unsigned int) - 1) / sizeof (unsigned int))
            union { double value; unsigned int word[NWORDS]; } m;

            /* Use a single integer to floating-point conversion.  */
            m.value = msd;

            s = GMP_LIMB_BITS
                - (((m.word[DBL_EXPBIT0_WORD] >> DBL_EXPBIT0_BIT) & DBL_EXP_MASK)
                   - DBL_EXP_BIAS);
          }
        else
#   undef NWORDS
#  endif
          {
            s = 31;
            if (msd >= 0x10000)
              {
                msd = msd >> 16;
                s -= 16;
              }
            if (msd >= 0x100)
              {
                msd = msd >> 8;
                s -= 8;
              }
            if (msd >= 0x10)
              {
                msd = msd >> 4;
                s -= 4;
              }
            if (msd >= 0x4)
              {
                msd = msd >> 2;
                s -= 2;
              }
            if (msd >= 0x2)
              {
                msd = msd >> 1;
                s -= 1;
              }
          }
# endif
      }
      /* 0 <= s < GMP_LIMB_BITS.
         Copy b, shifting it left by s bits.  */
      if (s > 0)
        {
          tmp_roomptr = (mp_limb_t *) malloc (b_len * sizeof (mp_limb_t));
          if (tmp_roomptr == NULL)
            {
              free (roomptr);
              return NULL;
            }
          {
            const mp_limb_t *sourceptr = b_ptr;
            mp_limb_t *destptr = tmp_roomptr;
            mp_twolimb_t accu = 0;
            size_t count;
            for (count = b_len; count > 0; count--)
              {
                accu += (mp_twolimb_t) *sourceptr++ << s;
                *destptr++ = (mp_limb_t) accu;
                accu = accu >> GMP_LIMB_BITS;
              }
            /* accu must be zero, since that was how s was determined.  */
            if (accu != 0)
              abort ();
          }
          b_ptr = tmp_roomptr;
        }
      /* Copy a, shifting it left by s bits, yields r.
         Memory layout:
         At the beginning: r = roomptr[0..a_len],
         at the end: r = roomptr[0..b_len-1], q = roomptr[b_len..a_len]  */
      r_ptr = roomptr;
      if (s == 0)
        {
          memcpy (r_ptr, a_ptr, a_len * sizeof (mp_limb_t));
          r_ptr[a_len] = 0;
        }
      else
        {
          const mp_limb_t *sourceptr = a_ptr;
          mp_limb_t *destptr = r_ptr;
          mp_twolimb_t accu = 0;
          size_t count;
          for (count = a_len; count > 0; count--)
            {
              accu += (mp_twolimb_t) *sourceptr++ << s;
              *destptr++ = (mp_limb_t) accu;
              accu = accu >> GMP_LIMB_BITS;
            }
          *destptr++ = (mp_limb_t) accu;
        }
      q_ptr = roomptr + b_len;
      q_len = a_len - b_len + 1; /* q will have m-n+1 limbs */
      {
        size_t j = a_len - b_len; /* m-n */
        mp_limb_t b_msd = b_ptr[b_len - 1]; /* b[n-1] */
        mp_limb_t b_2msd = b_ptr[b_len - 2]; /* b[n-2] */
        mp_twolimb_t b_msdd = /* b[n-1]*beta+b[n-2] */
          ((mp_twolimb_t) b_msd << GMP_LIMB_BITS) | b_2msd;
        /* Division loop, traversed m-n+1 times.
           j counts down, b is unchanged, beta/2 <= b[n-1] < beta.  */
        for (;;)
          {
            mp_limb_t q_star;
            mp_limb_t c1;
            if (r_ptr[j + b_len] < b_msd) /* r[j+n] < b[n-1] ? */
              {
                /* Divide r[j+n]*beta+r[j+n-1] by b[n-1], no overflow.  */
                mp_twolimb_t num =
                  ((mp_twolimb_t) r_ptr[j + b_len] << GMP_LIMB_BITS)
                  | r_ptr[j + b_len - 1];
                q_star = num / b_msd;
                c1 = num % b_msd;
              }
            else
              {
                /* Overflow, hence r[j+n]*beta+r[j+n-1] >= beta*b[n-1].  */
                q_star = (mp_limb_t)~(mp_limb_t)0; /* q* = beta-1 */
                /* Test whether r[j+n]*beta+r[j+n-1] - (beta-1)*b[n-1] >= beta
                   <==> r[j+n]*beta+r[j+n-1] + b[n-1] >= beta*b[n-1]+beta
                   <==> b[n-1] < floor((r[j+n]*beta+r[j+n-1]+b[n-1])/beta)
                        {<= beta !}.
                   If yes, jump directly to the subtraction loop.
                   (Otherwise, r[j+n]*beta+r[j+n-1] - (beta-1)*b[n-1] < beta
                    <==> floor((r[j+n]*beta+r[j+n-1]+b[n-1])/beta) = b[n-1] ) */
                if (r_ptr[j + b_len] > b_msd
                    || (c1 = r_ptr[j + b_len - 1] + b_msd) < b_msd)
                  /* r[j+n] >= b[n-1]+1 or
                     r[j+n] = b[n-1] and the addition r[j+n-1]+b[n-1] gives a
                     carry.  */
                  goto subtract;
              }
            /* q_star = q*,
               c1 = (r[j+n]*beta+r[j+n-1]) - q* * b[n-1] (>=0, <beta).  */
            {
              mp_twolimb_t c2 = /* c1*beta+r[j+n-2] */
                ((mp_twolimb_t) c1 << GMP_LIMB_BITS) | r_ptr[j + b_len - 2];
              mp_twolimb_t c3 = /* b[n-2] * q* */
                (mp_twolimb_t) b_2msd * (mp_twolimb_t) q_star;
              /* While c2 < c3, increase c2 and decrease c3.
                 Consider c3-c2.  While it is > 0, decrease it by
                 b[n-1]*beta+b[n-2].  Because of b[n-1]*beta+b[n-2] >= beta^2/2
                 this can happen only twice.  */
              if (c3 > c2)
                {
                  q_star = q_star - 1; /* q* := q* - 1 */
                  if (c3 - c2 > b_msdd)
                    q_star = q_star - 1; /* q* := q* - 1 */
                }
            }
            if (q_star > 0)
              subtract:
              {
                /* Subtract r := r - b * q* * beta^j.  */
                mp_limb_t cr;
                {
                  const mp_limb_t *sourceptr = b_ptr;
                  mp_limb_t *destptr = r_ptr + j;
                  mp_twolimb_t carry = 0;
                  size_t count;
                  for (count = b_len; count > 0; count--)
                    {
                      /* Here 0 <= carry <= q*.  */
                      carry =
                        carry
                        + (mp_twolimb_t) q_star * (mp_twolimb_t) *sourceptr++
                        + (mp_limb_t) ~(*destptr);
                      /* Here 0 <= carry <= beta*q* + beta-1.  */
                      *destptr++ = ~(mp_limb_t) carry;
                      carry = carry >> GMP_LIMB_BITS; /* <= q* */
                    }
                  cr = (mp_limb_t) carry;
                }
                /* Subtract cr from r_ptr[j + b_len], then forget about
                   r_ptr[j + b_len].  */
                if (cr > r_ptr[j + b_len])
                  {
                    /* Subtraction gave a carry.  */
                    q_star = q_star - 1; /* q* := q* - 1 */
                    /* Add b back.  */
                    {
                      const mp_limb_t *sourceptr = b_ptr;
                      mp_limb_t *destptr = r_ptr + j;
                      mp_limb_t carry = 0;
                      size_t count;
                      for (count = b_len; count > 0; count--)
                        {
                          mp_limb_t source1 = *sourceptr++;
                          mp_limb_t source2 = *destptr;
                          *destptr++ = source1 + source2 + carry;
                          carry =
                            (carry
                             ? source1 >= (mp_limb_t) ~source2
                             : source1 > (mp_limb_t) ~source2);
                        }
                    }
                    /* Forget about the carry and about r[j+n].  */
                  }
              }
            /* q* is determined.  Store it as q[j].  */
            q_ptr[j] = q_star;
            if (j == 0)
              break;
            j--;
          }
      }
      r_len = b_len;
      /* Normalise q.  */
      if (q_ptr[q_len - 1] == 0)
        q_len--;
# if 0 /* Not needed here, since we need r only to compare it with b/2, and
          b is shifted left by s bits.  */
      /* Shift r right by s bits.  */
      if (s > 0)
        {
          mp_limb_t ptr = r_ptr + r_len;
          mp_twolimb_t accu = 0;
          size_t count;
          for (count = r_len; count > 0; count--)
            {
              accu = (mp_twolimb_t) (mp_limb_t) accu << GMP_LIMB_BITS;
              accu += (mp_twolimb_t) *--ptr << (GMP_LIMB_BITS - s);
              *ptr = (mp_limb_t) (accu >> GMP_LIMB_BITS);
            }
        }
# endif
      /* Normalise r.  */
      while (r_len > 0 && r_ptr[r_len - 1] == 0)
        r_len--;
    }
  /* Compare r << 1 with b.  */
  if (r_len > b_len)
    goto increment_q;
  {
    size_t i;
    for (i = b_len;;)
      {
        mp_limb_t r_i =
          (i <= r_len && i > 0 ? r_ptr[i - 1] >> (GMP_LIMB_BITS - 1) : 0)
          | (i < r_len ? r_ptr[i] << 1 : 0);
        mp_limb_t b_i = (i < b_len ? b_ptr[i] : 0);
        if (r_i > b_i)
          goto increment_q;
        if (r_i < b_i)
          goto keep_q;
        if (i == 0)
          break;
        i--;
      }
  }
  if (q_len > 0 && ((q_ptr[0] & 1) != 0))
    /* q is odd.  */
    increment_q:
    {
      size_t i;
      for (i = 0; i < q_len; i++)
        if (++(q_ptr[i]) != 0)
          goto keep_q;
      q_ptr[q_len++] = 1;
    }
  keep_q:
  if (tmp_roomptr != NULL)
    free (tmp_roomptr);
  q->limbs = q_ptr;
  q->nlimbs = q_len;
  return roomptr;
}


static unsigned char *EncodeRLE(unsigned char *destination,
  unsigned char *source,size_t literal,size_t repeat)
{
  if (literal > 0)
    *destination++=(unsigned char) (literal-1);
  (void) memcpy(destination,source,literal);
  destination+=literal;
  if (repeat > 0)
    {
      *destination++=(unsigned char) (0x80 | (repeat-1));
      *destination++=source[literal];
    }
  return(destination);
}


ModuleExport size_t RegisterSGIImage(void)
{
  MagickInfo
    *entry;

  entry=AcquireMagickInfo("SGI","SGI","Irix RGB image");
  entry->decoder=(DecodeImageHandler *) ReadSGIImage;
  entry->encoder=(EncodeImageHandler *) WriteSGIImage;
  entry->magick=(IsImageFormatHandler *) IsSGI;
  entry->flags|=CoderDecoderSeekableStreamFlag;
  (void) RegisterMagickInfo(entry);
  return(MagickImageCoderSignature);
}


static int module_name(int argc, const char **argv, const char *prefix)
{
	const struct submodule *sub;

	if (argc != 2)
		usage(_("git submodule--helper name <path>"));

	gitmodules_config();
	sub = submodule_from_path(null_sha1, argv[1]);

	if (!sub)
		die(_("no submodule mapping found in .gitmodules for path '%s'"),
		    argv[1]);

	printf("%s\n", sub->name);

	return 0;
}


static int starts_with_dot_dot_slash(const char *str)
{
	return str[0] == '.' && str[1] == '.' && is_dir_sep(str[2]);
}


static int resolve_relative_url_test(int argc, const char **argv, const char *prefix)
{
	char *remoteurl, *res;
	const char *up_path, *url;

	if (argc != 4)
		die("resolve-relative-url-test only accepts three arguments: <up_path> <remoteurl> <url>");

	up_path = argv[1];
	remoteurl = xstrdup(argv[2]);
	url = argv[3];

	if (!strcmp(up_path, "(null)"))
		up_path = NULL;

	res = relative_url(remoteurl, url, up_path);
	puts(res);
	free(res);
	free(remoteurl);
	return 0;
}


static void cache_add(struct submodule_cache *cache,
		      struct submodule *submodule)
{
	unsigned int hash = hash_sha1_string(submodule->gitmodules_sha1,
					     submodule->name);
	struct submodule_entry *e = xmalloc(sizeof(*e));
	hashmap_entry_init(e, hash);
	e->config = submodule;
	hashmap_add(&cache->for_name, e);
}


int gitmodule_sha1_from_commit(const unsigned char *treeish_name,
				      unsigned char *gitmodules_sha1,
				      struct strbuf *rev)
{
	int ret = 0;

	if (is_null_sha1(treeish_name)) {
		hashclr(gitmodules_sha1);
		return 1;
	}

	strbuf_addf(rev, "%s:.gitmodules", sha1_to_hex(treeish_name));
	if (get_sha1(rev->buf, gitmodules_sha1) >= 0)
		ret = 1;

	return ret;
}


static int name_and_item_from_var(const char *var, struct strbuf *name,
				  struct strbuf *item)
{
	const char *subsection, *key;
	int subsection_len, parse;
	parse = parse_config_key(var, "submodule", &subsection,
			&subsection_len, &key);
	if (parse < 0 || !subsection)
		return 0;

	strbuf_add(name, subsection, subsection_len);
	if (check_submodule_name(name->buf) < 0) {
		warning(_("ignoring suspicious submodule name: %s"), name->buf);
		strbuf_release(name);
		return 0;
	}

	strbuf_addstr(item, key);

	return 1;
}


void submodule_free(void)
{
	if (the_repository->submodule_cache)
		submodule_cache_clear(the_repository->submodule_cache);
}


static int config_name_cmp(const void *unused_cmp_data,
			   const struct submodule_entry *a,
			   const struct submodule_entry *b,
			   const void *unused_keydata)
{
	return strcmp(a->config->name, b->config->name) ||
	       hashcmp(a->config->gitmodules_sha1, b->config->gitmodules_sha1);
}


static int fsck_commit_buffer(struct commit *commit, const char *buffer,
	unsigned long size, struct fsck_options *options)
{
	unsigned char tree_sha1[20], sha1[20];
	struct commit_graft *graft;
	unsigned parent_count, parent_line_count = 0, author_count;
	int err;
	const char *buffer_begin = buffer;

	if (verify_headers(buffer, size, &commit->object, options))
		return -1;

	if (!skip_prefix(buffer, "tree ", &buffer))
		return report(options, &commit->object, FSCK_MSG_MISSING_TREE, "invalid format - expected 'tree' line");
	if (get_sha1_hex(buffer, tree_sha1) || buffer[40] != '\n') {
		err = report(options, &commit->object, FSCK_MSG_BAD_TREE_SHA1, "invalid 'tree' line format - bad sha1");
		if (err)
			return err;
	}
	buffer += 41;
	while (skip_prefix(buffer, "parent ", &buffer)) {
		if (get_sha1_hex(buffer, sha1) || buffer[40] != '\n') {
			err = report(options, &commit->object, FSCK_MSG_BAD_PARENT_SHA1, "invalid 'parent' line format - bad sha1");
			if (err)
				return err;
		}
		buffer += 41;
		parent_line_count++;
	}
	graft = lookup_commit_graft(&commit->object.oid);
	parent_count = commit_list_count(commit->parents);
	if (graft) {
		if (graft->nr_parent == -1 && !parent_count)
			; /* shallow commit */
		else if (graft->nr_parent != parent_count) {
			err = report(options, &commit->object, FSCK_MSG_MISSING_GRAFT, "graft objects missing");
			if (err)
				return err;
		}
	} else {
		if (parent_count != parent_line_count) {
			err = report(options, &commit->object, FSCK_MSG_MISSING_PARENT, "parent objects missing");
			if (err)
				return err;
		}
	}
	author_count = 0;
	while (skip_prefix(buffer, "author ", &buffer)) {
		author_count++;
		err = fsck_ident(&buffer, &commit->object, options);
		if (err)
			return err;
	}
	if (author_count < 1)
		err = report(options, &commit->object, FSCK_MSG_MISSING_AUTHOR, "invalid format - expected 'author' line");
	else if (author_count > 1)
		err = report(options, &commit->object, FSCK_MSG_MULTIPLE_AUTHORS, "invalid format - multiple 'author' lines");
	if (err)
		return err;
	if (!skip_prefix(buffer, "committer ", &buffer))
		return report(options, &commit->object, FSCK_MSG_MISSING_COMMITTER, "invalid format - expected 'committer' line");
	err = fsck_ident(&buffer, &commit->object, options);
	if (err)
		return err;
	if (!commit->tree) {
		err = report(options, &commit->object, FSCK_MSG_BAD_TREE, "could not load commit's tree %s", sha1_to_hex(tree_sha1));
		if (err)
			return err;
	}
	if (memchr(buffer_begin, '\0', size)) {
		err = report(options, &commit->object, FSCK_MSG_NUL_IN_COMMIT,
			     "NUL byte in the commit object body");
		if (err)
			return err;
	}
	return 0;
}


int fsck_error_function(struct fsck_options *o,
	struct object *obj, int msg_type, const char *message)
{
	if (msg_type == FSCK_WARN) {
		warning("object %s: %s", describe_object(o, obj), message);
		return 0;
	}
	error("object %s: %s", describe_object(o, obj), message);
	return 1;
}


static void init_skiplist(struct fsck_options *options, const char *path)
{
	static struct oid_array skiplist = OID_ARRAY_INIT;
	int sorted, fd;
	char buffer[GIT_MAX_HEXSZ + 1];
	struct object_id oid;

	if (options->skiplist)
		sorted = options->skiplist->sorted;
	else {
		sorted = 1;
		options->skiplist = &skiplist;
	}

	fd = open(path, O_RDONLY);
	if (fd < 0)
		die("Could not open skip list: %s", path);
	for (;;) {
		const char *p;
		int result = read_in_full(fd, buffer, sizeof(buffer));
		if (result < 0)
			die_errno("Could not read '%s'", path);
		if (!result)
			break;
		if (parse_oid_hex(buffer, &oid, &p) || *p != '\n')
			die("Invalid SHA-1: %s", buffer);
		oid_array_append(&skiplist, &oid);
		if (sorted && skiplist.nr > 1 &&
				oidcmp(&skiplist.oid[skiplist.nr - 2],
				       &oid) > 0)
			sorted = 0;
	}
	close(fd);

	if (sorted)
		skiplist.sorted = 1;
}


static void put_object_name(struct fsck_options *options, struct object *obj,
	const char *fmt, ...)
{
	va_list ap;
	struct strbuf buf = STRBUF_INIT;
	char *existing;

	if (!options->object_names)
		return;
	existing = lookup_decoration(options->object_names, obj);
	if (existing)
		return;
	va_start(ap, fmt);
	strbuf_vaddf(&buf, fmt, ap);
	add_decoration(options->object_names, obj, strbuf_detach(&buf, NULL));
	va_end(ap);
}


static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, const char *name2)
{
	int len1 = strlen(name1);
	int len2 = strlen(name2);
	int len = len1 < len2 ? len1 : len2;
	unsigned char c1, c2;
	int cmp;

	cmp = memcmp(name1, name2, len);
	if (cmp < 0)
		return 0;
	if (cmp > 0)
		return TREE_UNORDERED;

	/*
	 * Ok, the first <len> characters are the same.
	 * Now we need to order the next one, but turn
	 * a '\0' into a '/' for a directory entry.
	 */
	c1 = name1[len];
	c2 = name2[len];
	if (!c1 && !c2)
		/*
		 * git-write-tree used to write out a nonsense tree that has
		 * entries with the same name, one blob and one tree.  Make
		 * sure we do not have duplicate entries.
		 */
		return TREE_HAS_DUPS;
	if (!c1 && S_ISDIR(mode1))
		c1 = '/';
	if (!c2 && S_ISDIR(mode2))
		c2 = '/';
	return c1 < c2 ? 0 : TREE_UNORDERED;
}


static int fsck_walk_tag(struct tag *tag, void *data, struct fsck_options *options)
{
	char *name = get_object_name(options, &tag->object);

	if (parse_tag(tag))
		return -1;
	if (name)
		put_object_name(options, tag->tagged, "%s", name);
	return options->walk(tag->tagged, OBJ_ANY, data, options);
}


static int fsck_msg_type(enum fsck_msg_id msg_id,
	struct fsck_options *options)
{
	int msg_type;

	assert(msg_id >= 0 && msg_id < FSCK_MSG_MAX);

	if (options->msg_type)
		msg_type = options->msg_type[msg_id];
	else {
		msg_type = msg_id_info[msg_id].msg_type;
		if (options->strict && msg_type == FSCK_WARN)
			msg_type = FSCK_ERROR;
	}

	return msg_type;
}


void hmp_info_network(Monitor *mon, const QDict *qdict)
{
    NetClientState *nc, *peer;
    NetClientDriver type;

    net_hub_info(mon);

    QTAILQ_FOREACH(nc, &net_clients, next) {
        peer = nc->peer;
        type = nc->info->type;

        /* Skip if already printed in hub info */
        if (net_hub_id_for_client(nc, NULL) == 0) {
            continue;
        }

        if (!peer || type == NET_CLIENT_DRIVER_NIC) {
            print_net_client(mon, nc);
        } /* else it's a netdev connected to a NIC, printed with the NIC */
        if (peer && type == NET_CLIENT_DRIVER_NIC) {
            monitor_printf(mon, " \\ ");
            print_net_client(mon, peer);
        }
    }
}


bool qemu_has_vnet_hdr(NetClientState *nc)
{
    if (!nc || !nc->info->has_vnet_hdr) {
        return false;
    }

    return nc->info->has_vnet_hdr(nc);
}


void qemu_del_nic(NICState *nic)
{
    int i, queues = MAX(nic->conf->peers.queues, 1);

    qemu_macaddr_set_free(&nic->conf->macaddr);

    /* If this is a peer NIC and peer has already been deleted, free it now. */
    if (nic->peer_deleted) {
        for (i = 0; i < queues; i++) {
            qemu_free_net_client(qemu_get_subqueue(nic, i)->peer);
        }
    }

    for (i = queues - 1; i >= 0; i--) {
        NetClientState *nc = qemu_get_subqueue(nic, i);

        qemu_cleanup_net_client(nc);
        qemu_free_net_client(nc);
    }

    g_free(nic);
}


int qemu_set_vnet_le(NetClientState *nc, bool is_le)
{
#ifdef HOST_WORDS_BIGENDIAN
    if (!nc || !nc->info->set_vnet_le) {
        return -ENOSYS;
    }

    return nc->info->set_vnet_le(nc, is_le);
#else
    return 0;
#endif
}


static void net_vm_change_state_handler(void *opaque, int running,
                                        RunState state)
{
    NetClientState *nc;
    NetClientState *tmp;

    QTAILQ_FOREACH_SAFE(nc, &net_clients, next, tmp) {
        if (running) {
            /* Flush queued packets and wake up backends. */
            if (nc->peer && qemu_can_send_packet(nc)) {
                qemu_flush_queued_packets(nc->peer);
            }
        } else {
            /* Complete all queued packets, to guarantee we don't modify
             * state later when VM is not running.
             */
            qemu_flush_or_purge_queued_packets(nc, true);
        }
    }
}


static int SVGHasInternalSubset(void *context)
{
  SVGInfo
    *svg_info;

  /*
    Does this document has an internal subset?
  */
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
    "  SAX.SVGHasInternalSubset()");
  svg_info=(SVGInfo *) context;
  return(svg_info->document->intSubset != NULL);
}


ddxGiveUp(enum ExitCode error)
{
    int i;

    xf86VGAarbiterFini();

#ifdef XF86PM
    if (xf86OSPMClose)
        xf86OSPMClose();
    xf86OSPMClose = NULL;
#endif

    for (i = 0; i < xf86NumScreens; i++) {
        /*
         * zero all access functions to
         * trap calls when switched away.
         */
        xf86Screens[i]->vtSema = FALSE;
    }

#ifdef XFreeXDGA
    DGAShutdown();
#endif

    if (xorgHWOpenConsole)
        xf86CloseConsole();

    systemd_logind_fini();
    dbus_core_fini();

    xf86CloseLog(error);

    /* If an unexpected signal was caught, dump a core for debugging */
    if (xf86Info.caughtSignal)
        OsAbort();
}


AbortDDX(enum ExitCode error)
{
    int i;

    input_lock();

    /*
     * try to restore the original video state
     */
#ifdef DPMSExtension            /* Turn screens back on */
    if (DPMSPowerLevel != DPMSModeOn)
        DPMSSet(serverClient, DPMSModeOn);
#endif
    if (xf86Screens) {
        for (i = 0; i < xf86NumScreens; i++)
            if (xf86Screens[i]->vtSema) {
                /*
                 * if we are aborting before ScreenInit() has finished
                 * we might not have been wrapped yet. Therefore enable
                 * screen explicitely.
                 */
                xf86VGAarbiterLock(xf86Screens[i]);
                (xf86Screens[i]->LeaveVT) (xf86Screens[i]);
                xf86VGAarbiterUnlock(xf86Screens[i]);
            }
    }

    /*
     * This is needed for an abnormal server exit, since the normal exit stuff
     * MUST also be performed (i.e. the vt must be left in a defined state)
     */
    ddxGiveUp(error);
}


LogVMessageVerb(MessageType type, int verb, const char *format, va_list args)
{
    const char *type_str;
    char buf[1024];
    const size_t size = sizeof(buf);
    Bool newline;
    size_t len = 0;

    if (inSignalContext) {
        LogVMessageVerbSigSafe(type, verb, format, args);
        return;
    }

    type_str = LogMessageTypeVerbString(type, verb);
    if (!type_str)
        return;

    /* if type_str is not "", prepend it and ' ', to message */
    if (type_str[0] != '\0')
        len += Xscnprintf(&buf[len], size - len, "%s ", type_str);

    if (size - len > 1)
        len += Xvscnprintf(&buf[len], size - len, format, args);

    /* Force '\n' at end of truncated line */
    if (size - len == 1)
        buf[len - 1] = '\n';

    newline = (buf[len - 1] == '\n');
    LogSWrite(verb, buf, len, newline);
}


FatalError(const char *f, ...)
{
    va_list args;
    va_list args2;
    static Bool beenhere = FALSE;

    if (beenhere)
        ErrorFSigSafe("\nFatalError re-entered, aborting\n");
    else
        ErrorFSigSafe("\nFatal server error:\n");

    va_start(args, f);

    /* Make a copy for OsVendorFatalError */
    va_copy(args2, args);

#ifdef __APPLE__
    {
        va_list apple_args;

        va_copy(apple_args, args);
        (void)vsnprintf(__crashreporter_info_buff__,
                        sizeof(__crashreporter_info_buff__), f, apple_args);
        va_end(apple_args);
    }
#endif
    VErrorFSigSafe(f, args);
    va_end(args);
    ErrorFSigSafe("\n");
    if (!beenhere)
        OsVendorFatalError(f, args2);
    va_end(args2);
    if (!beenhere) {
        beenhere = TRUE;
        AbortServer();
    }
    else
        OsAbort();
 /*NOTREACHED*/}


LogMessageVerbSigSafe(MessageType type, int verb, const char *format, ...)
{
    va_list ap;
    va_start(ap, format);
    LogVMessageVerbSigSafe(type, verb, format, ap);
    va_end(ap);
}


int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn) {
        uint8_t buffer[1 + DNS_WIRE_FORMAT_HOSTNAME_MAX];
        int r;

        assert_return(buf && *buf && buflen && fqdn, -EINVAL);

        buffer[0] = DHCP6_FQDN_FLAG_S; /* Request server to perform AAAA RR DNS updates */

        /* Store domain name after flags field */
        r = dns_name_to_wire_format(fqdn, buffer + 1, sizeof(buffer) - 1,  false);
        if (r <= 0)
                return r;

        /*
         * According to RFC 4704, chapter 4.2 only add terminating zero-length
         * label in case a FQDN is provided. Since dns_name_to_wire_format
         * always adds terminating zero-length label remove if only a hostname
         * is provided.
         */
        if (dns_name_is_single_label(fqdn))
                r--;

        r = dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_FQDN, 1 + r, buffer);

        return r;
}


void manager_dirty(Manager *manager) {
        assert(manager);

        /* the serialized state in /run is no longer up-to-date */
        manager->dirty = true;
}


static int link_handle_bound_to_list(Link *link) {
        Link *l;
        Iterator i;
        int r;
        bool required_up = false;
        bool link_is_up = false;

        assert(link);

        if (hashmap_isempty(link->bound_to_links))
                return 0;

        if (link->flags & IFF_UP)
                link_is_up = true;

        HASHMAP_FOREACH (l, link->bound_to_links, i)
                if (link_has_carrier(l)) {
                        required_up = true;
                        break;
                }

        if (!required_up && link_is_up) {
                r = link_down(link);
                if (r < 0)
                        return r;
        } else if (required_up && !link_is_up) {
                r = link_up(link);
                if (r < 0)
                        return r;
        }

        return 0;
}


int manager_run(Manager *m) {
        Link *link;
        Iterator i;

        assert(m);

        /* The dirty handler will deal with future serialization, but the first one
           must be done explicitly. */

        manager_save(m);

        HASHMAP_FOREACH(link, m->links, i)
                link_save(link);

        if (m->bus)
                return bus_event_loop_with_idle(
                                m->event,
                                m->bus,
                                "org.freedesktop.network1",
                                DEFAULT_EXIT_USEC,
                                manager_check_idle,
                                m);
        else
                /* failed to connect to the bus, so we lose exit-on-idle logic,
                   this should not happen except if dbus is not around at all */
                return sd_event_loop(m->event);
}


static int link_put_carrier(Link *link, Link *carrier, Hashmap **h) {
        int r;

        assert(link);
        assert(carrier);

        if (link == carrier)
                return 0;

        if (hashmap_get(*h, INT_TO_PTR(carrier->ifindex)))
                return 0;

        r = hashmap_ensure_allocated(h, NULL);
        if (r < 0)
                return r;

        r = hashmap_put(*h, INT_TO_PTR(carrier->ifindex), carrier);
        if (r < 0)
                return r;

        return 0;
}


static void link_free_bound_to_list(Link *link) {
        Link *bound_to;
        Iterator i;

        HASHMAP_FOREACH (bound_to, link->bound_to_links, i) {
                hashmap_remove(link->bound_to_links, INT_TO_PTR(bound_to->ifindex));

                if (hashmap_remove(bound_to->bound_by_links, INT_TO_PTR(link->ifindex)))
                        link_dirty(bound_to);
        }

        return;
}


int link_get(Manager *m, int ifindex, Link **ret) {
        Link *link;

        assert(m);
        assert(ifindex);
        assert(ret);

        link = hashmap_get(m->links, INT_TO_PTR(ifindex));
        if (!link)
                return -ENODEV;

        *ret = link;

        return 0;
}


static int manager_save(Manager *m) {
        _cleanup_set_free_free_ Set *dns = NULL, *ntp = NULL, *domains = NULL;
        Link *link;
        Iterator i;
        _cleanup_free_ char *temp_path = NULL;
        _cleanup_fclose_ FILE *f = NULL;
        LinkOperationalState operstate = LINK_OPERSTATE_OFF;
        const char *operstate_str;
        int r;

        assert(m);
        assert(m->state_file);

        /* We add all NTP and DNS server to a set, to filter out duplicates */
        dns = set_new(&string_hash_ops);
        if (!dns)
                return -ENOMEM;

        ntp = set_new(&string_hash_ops);
        if (!ntp)
                return -ENOMEM;

        domains = set_new(&string_hash_ops);
        if (!domains)
                return -ENOMEM;

        HASHMAP_FOREACH(link, m->links, i) {
                if (link->flags & IFF_LOOPBACK)
                        continue;

                if (link->operstate > operstate)
                        operstate = link->operstate;

                if (!link->network)
                        continue;

                /* First add the static configured entries */
                r = set_put_strdupv(dns, link->network->dns);
                if (r < 0)
                        return r;

                r = set_put_strdupv(ntp, link->network->ntp);
                if (r < 0)
                        return r;

                r = set_put_strdupv(domains, link->network->domains);
                if (r < 0)
                        return r;

                if (!link->dhcp_lease)
                        continue;

                /* Secondly, add the entries acquired via DHCP */
                if (link->network->dhcp_dns) {
                        const struct in_addr *addresses;

                        r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
                        if (r > 0) {
                                r = set_put_in_addrv(dns, addresses, r);
                                if (r < 0)
                                        return r;
                        } else if (r < 0 && r != -ENODATA)
                                return r;
                }

                if (link->network->dhcp_ntp) {
                        const struct in_addr *addresses;

                        r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
                        if (r > 0) {
                                r = set_put_in_addrv(ntp, addresses, r);
                                if (r < 0)
                                        return r;
                        } else if (r < 0 && r != -ENODATA)
                                return r;
                }

                if (link->network->dhcp_domains) {
                        const char *domainname;

                        r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
                        if (r >= 0) {
                                r = set_put_strdup(domains, domainname);
                                if (r < 0)
                                        return r;
                        } else if (r != -ENODATA)
                                return r;
                }
        }

        operstate_str = link_operstate_to_string(operstate);
        assert(operstate_str);

        r = fopen_temporary(m->state_file, &f, &temp_path);
        if (r < 0)
                return r;

        fchmod(fileno(f), 0644);

        fprintf(f,
                "# This is private data. Do not parse.\n"
                "OPER_STATE=%s\n", operstate_str);

        print_string_set(f, "DNS=", dns);
        print_string_set(f, "NTP=", ntp);
        print_string_set(f, "DOMAINS=", domains);

        r = fflush_and_check(f);
        if (r < 0)
                goto fail;

        if (rename(temp_path, m->state_file) < 0) {
                r = -errno;
                goto fail;
        }

        if (m->operational_state != operstate) {
                m->operational_state = operstate;
                r = manager_send_changed(m, "OperationalState", NULL);
                if (r < 0)
                        log_error_errno(r, "Could not emit changed OperationalState: %m");
        }

        m->dirty = false;

        return 0;

fail:
        (void) unlink(m->state_file);
        (void) unlink(temp_path);

        return log_error_errno(r, "Failed to save network state to %s: %m", m->state_file);
}