do_replace(struct net *net, sockptr_t arg, unsigned int len)
{
	int ret;
	struct ip6t_replace tmp;
	struct xt_table_info *newinfo;
	void *loc_cpu_entry;
	struct ip6t_entry *iter;

	if (copy_from_sockptr(&tmp, arg, sizeof(tmp)) != 0)
		return -EFAULT;

	/* overflow check */
	if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
		return -ENOMEM;
	if (tmp.num_counters == 0)
		return -EINVAL;

	tmp.name[sizeof(tmp.name)-1] = 0;

	newinfo = xt_alloc_table_info(tmp.size);
	if (!newinfo)
		return -ENOMEM;

	loc_cpu_entry = newinfo->entries;
	if (copy_from_sockptr_offset(loc_cpu_entry, arg, sizeof(tmp),
			tmp.size) != 0) {
		ret = -EFAULT;
		goto free_newinfo;
	}

	ret = translate_table(net, newinfo, loc_cpu_entry, &tmp);
	if (ret != 0)
		goto free_newinfo;

	ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
			   tmp.num_counters, tmp.counters);
	if (ret)
		goto free_newinfo_untrans;
	return 0;

 free_newinfo_untrans:
	xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
		cleanup_entry(iter, net);
 free_newinfo:
	xt_free_table_info(newinfo);
	return ret;
}


translate_compat_table(struct net *net,
		       struct xt_table_info **pinfo,
		       void **pentry0,
		       const struct compat_ipt_replace *compatr)
{
	unsigned int i, j;
	struct xt_table_info *newinfo, *info;
	void *pos, *entry0, *entry1;
	struct compat_ipt_entry *iter0;
	struct ipt_replace repl;
	unsigned int size;
	int ret;

	info = *pinfo;
	entry0 = *pentry0;
	size = compatr->size;
	info->number = compatr->num_entries;

	j = 0;
	xt_compat_lock(AF_INET);
	ret = xt_compat_init_offsets(AF_INET, compatr->num_entries);
	if (ret)
		goto out_unlock;
	/* Walk through entries, checking offsets. */
	xt_entry_foreach(iter0, entry0, compatr->size) {
		ret = check_compat_entry_size_and_hooks(iter0, info, &size,
							entry0,
							entry0 + compatr->size);
		if (ret != 0)
			goto out_unlock;
		++j;
	}

	ret = -EINVAL;
	if (j != compatr->num_entries)
		goto out_unlock;

	ret = -ENOMEM;
	newinfo = xt_alloc_table_info(size);
	if (!newinfo)
		goto out_unlock;

	memset(newinfo->entries, 0, size);

	newinfo->number = compatr->num_entries;
	for (i = 0; i < NF_INET_NUMHOOKS; i++) {
		newinfo->hook_entry[i] = compatr->hook_entry[i];
		newinfo->underflow[i] = compatr->underflow[i];
	}
	entry1 = newinfo->entries;
	pos = entry1;
	size = compatr->size;
	xt_entry_foreach(iter0, entry0, compatr->size)
		compat_copy_entry_from_user(iter0, &pos, &size,
					    newinfo, entry1);

	/* all module references in entry0 are now gone.
	 * entry1/newinfo contains a 64bit ruleset that looks exactly as
	 * generated by 64bit userspace.
	 *
	 * Call standard translate_table() to validate all hook_entrys,
	 * underflows, check for loops, etc.
	 */
	xt_compat_flush_offsets(AF_INET);
	xt_compat_unlock(AF_INET);

	memcpy(&repl, compatr, sizeof(*compatr));

	for (i = 0; i < NF_INET_NUMHOOKS; i++) {
		repl.hook_entry[i] = newinfo->hook_entry[i];
		repl.underflow[i] = newinfo->underflow[i];
	}

	repl.num_counters = 0;
	repl.counters = NULL;
	repl.size = newinfo->size;
	ret = translate_table(net, newinfo, entry1, &repl);
	if (ret)
		goto free_newinfo;

	*pinfo = newinfo;
	*pentry0 = entry1;
	xt_free_table_info(info);
	return 0;

free_newinfo:
	xt_free_table_info(newinfo);
	return ret;
out_unlock:
	xt_compat_flush_offsets(AF_INET);
	xt_compat_unlock(AF_INET);
	xt_entry_foreach(iter0, entry0, compatr->size) {
		if (j-- == 0)
			break;
		compat_release_entry(iter0);
	}
	return ret;
}


void arpt_unregister_table(struct net *net, struct xt_table *table)
{
	__arpt_unregister_table(net, table);
}


static int get_info(struct net *net, void __user *user, const int *len)
{
	char name[XT_TABLE_MAXNAMELEN];
	struct xt_table *t;
	int ret;

	if (*len != sizeof(struct ip6t_getinfo))
		return -EINVAL;

	if (copy_from_user(name, user, sizeof(name)) != 0)
		return -EFAULT;

	name[XT_TABLE_MAXNAMELEN-1] = '\0';
#ifdef CONFIG_COMPAT
	if (in_compat_syscall())
		xt_compat_lock(AF_INET6);
#endif
	t = xt_request_find_table_lock(net, AF_INET6, name);
	if (!IS_ERR(t)) {
		struct ip6t_getinfo info;
		const struct xt_table_info *private = t->private;
#ifdef CONFIG_COMPAT
		struct xt_table_info tmp;

		if (in_compat_syscall()) {
			ret = compat_table_info(private, &tmp);
			xt_compat_flush_offsets(AF_INET6);
			private = &tmp;
		}
#endif
		memset(&info, 0, sizeof(info));
		info.valid_hooks = t->valid_hooks;
		memcpy(info.hook_entry, private->hook_entry,
		       sizeof(info.hook_entry));
		memcpy(info.underflow, private->underflow,
		       sizeof(info.underflow));
		info.num_entries = private->number;
		info.size = private->size;
		strcpy(info.name, name);

		if (copy_to_user(user, &info, *len) != 0)
			ret = -EFAULT;
		else
			ret = 0;

		xt_table_unlock(t);
		module_put(t->me);
	} else
		ret = PTR_ERR(t);
#ifdef CONFIG_COMPAT
	if (in_compat_syscall())
		xt_compat_unlock(AF_INET6);
#endif
	return ret;
}


static int compat_do_replace(struct net *net, sockptr_t arg, unsigned int len)
{
	int ret;
	struct compat_arpt_replace tmp;
	struct xt_table_info *newinfo;
	void *loc_cpu_entry;
	struct arpt_entry *iter;

	if (copy_from_sockptr(&tmp, arg, sizeof(tmp)) != 0)
		return -EFAULT;

	/* overflow check */
	if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
		return -ENOMEM;
	if (tmp.num_counters == 0)
		return -EINVAL;

	tmp.name[sizeof(tmp.name)-1] = 0;

	newinfo = xt_alloc_table_info(tmp.size);
	if (!newinfo)
		return -ENOMEM;

	loc_cpu_entry = newinfo->entries;
	if (copy_from_sockptr_offset(loc_cpu_entry, arg, sizeof(tmp),
			tmp.size) != 0) {
		ret = -EFAULT;
		goto free_newinfo;
	}

	ret = translate_compat_table(net, &newinfo, &loc_cpu_entry, &tmp);
	if (ret != 0)
		goto free_newinfo;

	ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
			   tmp.num_counters, compat_ptr(tmp.counters));
	if (ret)
		goto free_newinfo_untrans;
	return 0;

 free_newinfo_untrans:
	xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
		cleanup_entry(iter, net);
 free_newinfo:
	xt_free_table_info(newinfo);
	return ret;
}


compat_calc_match(struct ipt_entry_match *m, int * size)
{
	*size += xt_compat_match_offset(m->u.kernel.match);
	return 0;
}


get_counters(const struct xt_table_info *t,
	     struct xt_counters counters[])
{
	unsigned int cpu;
	unsigned int i;
	unsigned int curcpu;

	/* Instead of clearing (by a previous call to memset())
	 * the counters and using adds, we set the counters
	 * with data used by 'current' CPU
	 * We dont care about preemption here.
	 */
	curcpu = raw_smp_processor_id();

	i = 0;
	IPT_ENTRY_ITERATE(t->entries[curcpu],
			  t->size,
			  set_entry_to_counter,
			  counters,
			  &i);

	for_each_possible_cpu(cpu) {
		if (cpu == curcpu)
			continue;
		i = 0;
		IPT_ENTRY_ITERATE(t->entries[cpu],
				  t->size,
				  add_entry_to_counter,
				  counters,
				  &i);
	}
}


static void *xt_tgt_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
	struct proc_dir_entry *pde = seq->private;
	u_int16_t af = (unsigned long)pde->data & 0xffff;
	u_int16_t type = (unsigned long)pde->data >> 16;
	struct list_head *list;

	if (af >= NPROTO)
		return NULL;

	list = type2list(af, type);
	if (!list)
		return NULL;

	(*pos)++;
	return xt_get_idx(list, seq, *pos);
}


int xt_compat_match_offset(struct xt_match *match)
{
	u_int16_t csize = match->compatsize ? : match->matchsize;
	return XT_ALIGN(match->matchsize) - COMPAT_XT_ALIGN(csize);
}


check_entry_size_and_hooks(struct ipt_entry *e,
			   struct xt_table_info *newinfo,
			   unsigned char *base,
			   unsigned char *limit,
			   const unsigned int *hook_entries,
			   const unsigned int *underflows,
			   unsigned int *i)
{
	unsigned int h;

	if ((unsigned long)e % __alignof__(struct ipt_entry) != 0
	    || (unsigned char *)e + sizeof(struct ipt_entry) >= limit) {
		duprintf("Bad offset %p\n", e);
		return -EINVAL;
	}

	if (e->next_offset
	    < sizeof(struct ipt_entry) + sizeof(struct ipt_entry_target)) {
		duprintf("checking: element %p size %u\n",
			 e, e->next_offset);
		return -EINVAL;
	}

	/* Check hooks & underflows */
	for (h = 0; h < NF_IP_NUMHOOKS; h++) {
		if ((unsigned char *)e - base == hook_entries[h])
			newinfo->hook_entry[h] = hook_entries[h];
		if ((unsigned char *)e - base == underflows[h])
			newinfo->underflow[h] = underflows[h];
	}

	/* FIXME: underflows must be unconditional, standard verdicts
           < 0 (not IPT_RETURN). --RR */

	/* Clear counters and comefrom */
	e->counters = ((struct xt_counters) { 0, 0 });
	e->comefrom = 0;

	(*i)++;
	return 0;
}


void *xt_unregister_table(struct xt_table *table)
{
	struct xt_table_info *private;

	mutex_lock(&xt[table->af].mutex);
	private = table->private;
	list_del(&table->list);
	mutex_unlock(&xt[table->af].mutex);

	return private;
}


static inline struct xt_counters * alloc_counters(struct ipt_table *table)
{
	unsigned int countersize;
	struct xt_counters *counters;
	struct xt_table_info *private = table->private;

	/* We need atomic snapshot of counters: rest doesn't change
	   (other than comefrom, which userspace doesn't care
	   about). */
	countersize = sizeof(struct xt_counters) * private->number;
	counters = vmalloc_node(countersize, numa_node_id());

	if (counters == NULL)
		return ERR_PTR(-ENOMEM);

	/* First, sum counters... */
	write_lock_bh(&table->lock);
	get_counters(private, counters);
	write_unlock_bh(&table->lock);

	return counters;
}


int xt_compat_target_offset(struct xt_target *target)
{
	u_int16_t csize = target->compatsize ? : target->targetsize;
	return XT_ALIGN(target->targetsize) - COMPAT_XT_ALIGN(csize);
}


add_entry_to_counter(const struct ipt_entry *e,
		     struct xt_counters total[],
		     unsigned int *i)
{
	ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);

	(*i)++;
	return 0;
}


do_add_counters(void __user *user, unsigned int len, int compat)
{
	unsigned int i;
	struct xt_counters_info tmp;
	struct xt_counters *paddc;
	unsigned int num_counters;
	char *name;
	int size;
	void *ptmp;
	struct ipt_table *t;
	struct xt_table_info *private;
	int ret = 0;
	void *loc_cpu_entry;
#ifdef CONFIG_COMPAT
	struct compat_xt_counters_info compat_tmp;

	if (compat) {
		ptmp = &compat_tmp;
		size = sizeof(struct compat_xt_counters_info);
	} else
#endif
	{
		ptmp = &tmp;
		size = sizeof(struct xt_counters_info);
	}

	if (copy_from_user(ptmp, user, size) != 0)
		return -EFAULT;

#ifdef CONFIG_COMPAT
	if (compat) {
		num_counters = compat_tmp.num_counters;
		name = compat_tmp.name;
	} else
#endif
	{
		num_counters = tmp.num_counters;
		name = tmp.name;
	}

	if (len != size + num_counters * sizeof(struct xt_counters))
		return -EINVAL;

	paddc = vmalloc_node(len - size, numa_node_id());
	if (!paddc)
		return -ENOMEM;

	if (copy_from_user(paddc, user + size, len - size) != 0) {
		ret = -EFAULT;
		goto free;
	}

	t = xt_find_table_lock(AF_INET, name);
	if (!t || IS_ERR(t)) {
		ret = t ? PTR_ERR(t) : -ENOENT;
		goto free;
	}

	write_lock_bh(&t->lock);
	private = t->private;
	if (private->number != num_counters) {
		ret = -EINVAL;
		goto unlock_up_free;
	}

	i = 0;
	/* Choose the copy that is on our node */
	loc_cpu_entry = private->entries[raw_smp_processor_id()];
	IPT_ENTRY_ITERATE(loc_cpu_entry,
			  private->size,
			  add_counter_to_entry,
			  paddc,
			  &i);
 unlock_up_free:
	write_unlock_bh(&t->lock);
	xt_table_unlock(t);
	module_put(t->me);
 free:
	vfree(paddc);

	return ret;
}


xt_unregister_targets(struct xt_target *target, unsigned int n)
{
	unsigned int i;

	for (i = 0; i < n; i++)
		xt_unregister_target(&target[i]);
}


static int compat_table_info(struct xt_table_info *info,
		struct xt_table_info *newinfo)
{
	void *loc_cpu_entry;
	int i;

	if (!newinfo || !info)
		return -EINVAL;

	memset(newinfo, 0, sizeof(struct xt_table_info));
	newinfo->size = info->size;
	newinfo->number = info->number;
	for (i = 0; i < NF_IP_NUMHOOKS; i++) {
		newinfo->hook_entry[i] = info->hook_entry[i];
		newinfo->underflow[i] = info->underflow[i];
	}
	loc_cpu_entry = info->entries[raw_smp_processor_id()];
	return IPT_ENTRY_ITERATE(loc_cpu_entry, info->size,
			compat_calc_entry, info, loc_cpu_entry, newinfo);
}


static int bcf_hdr_set_idx(bcf_hdr_t *hdr, int dict_type, const char *tag, bcf_idinfo_t *idinfo)
{
    size_t new_n;

    // If available, preserve existing IDX
    if ( idinfo->id==-1 )
        idinfo->id = hdr->n[dict_type];
    else if ( idinfo->id < hdr->n[dict_type] && hdr->id[dict_type][idinfo->id].key )
    {
        hts_log_error("Conflicting IDX=%d lines in the header dictionary, the new tag is %s",
            idinfo->id, tag);
        errno = EINVAL;
        return -1;
    }

    new_n = idinfo->id >= hdr->n[dict_type] ? idinfo->id+1 : hdr->n[dict_type];
    if (hts_resize(bcf_idpair_t, new_n, &hdr->m[dict_type],
                   &hdr->id[dict_type], HTS_RESIZE_CLEAR)) {
        return -1;
    }
    hdr->n[dict_type] = new_n;

    // NB: the next kh_put call can invalidate the idinfo pointer, therefore
    // we leave it unassigned here. It must be set explicitly in bcf_hdr_sync.
    hdr->id[dict_type][idinfo->id].key = tag;

    return 0;
}


bcf_info_t *bcf_get_info_id(bcf1_t *line, const int id)
{
    int i;
    if ( !(line->unpacked & BCF_UN_INFO) ) bcf_unpack(line, BCF_UN_INFO);
    for (i=0; i<line->n_info; i++)
    {
        if ( line->d.info[i].key==id ) return &line->d.info[i];
    }
    return NULL;
}


bcf1_t *bcf_dup(bcf1_t *src)
{
    bcf1_t *out = bcf_init1();
    return bcf_copy(out, src);
}


static inline int bcf_read1_core(BGZF *fp, bcf1_t *v)
{
    uint8_t x[32];
    ssize_t ret;
    uint32_t shared_len, indiv_len;
    if ((ret = bgzf_read(fp, x, 32)) != 32) {
        if (ret == 0) return -1;
        return -2;
    }
    bcf_clear1(v);
    shared_len = le_to_u32(x);
    if (shared_len < 24) return -2;
    shared_len -= 24; // to exclude six 32-bit integers
    if (ks_resize(&v->shared, shared_len) != 0) return -2;
    indiv_len = le_to_u32(x + 4);
    if (ks_resize(&v->indiv, indiv_len) != 0) return -2;
    v->rid  = le_to_i32(x + 8);
    v->pos  = le_to_u32(x + 12);
    v->rlen = le_to_i32(x + 16);
    v->qual = le_to_float(x + 20);
    v->n_info = le_to_u16(x + 24);
    v->n_allele = le_to_u16(x + 26);
    v->n_sample = le_to_u32(x + 28) & 0xffffff;
    v->n_fmt = x[31];
    v->shared.l = shared_len;
    v->indiv.l = indiv_len;
    // silent fix of broken BCFs produced by earlier versions of bcf_subset, prior to and including bd6ed8b4
    if ( (!v->indiv.l || !v->n_sample) && v->n_fmt ) v->n_fmt = 0;

    if (bgzf_read(fp, v->shared.s, v->shared.l) != v->shared.l) return -2;
    if (bgzf_read(fp, v->indiv.s, v->indiv.l) != v->indiv.l) return -2;
    return 0;
}


int bcf_read(htsFile *fp, const bcf_hdr_t *h, bcf1_t *v)
{
    if (fp->format.format == vcf) return vcf_read(fp,h,v);
    int ret = bcf_read1_core(fp->fp.bgzf, v);
    if (ret == 0) ret = bcf_record_check(h, v);
    if ( ret!=0 || !h->keep_samples ) return ret;
    return bcf_subset_format(h,v);
}


int bcf_translate(const bcf_hdr_t *dst_hdr, bcf_hdr_t *src_hdr, bcf1_t *line)
{
    int i;
    if ( line->errcode )
    {
        hts_log_error("Unchecked error (%d) at %s:%"PRIhts_pos", exiting", line->errcode, bcf_seqname_safe(src_hdr,line), line->pos+1);
        exit(1);
    }
    if ( src_hdr->ntransl==-1 ) return 0;    // no need to translate, all tags have the same id
    if ( !src_hdr->ntransl )  // called for the first time, see what needs translating
    {
        int dict;
        for (dict=0; dict<2; dict++)    // BCF_DT_ID and BCF_DT_CTG
        {
            src_hdr->transl[dict] = (int*) malloc(src_hdr->n[dict]*sizeof(int));
            for (i=0; i<src_hdr->n[dict]; i++)
            {
                if ( !src_hdr->id[dict][i].key ) // gap left after removed BCF header lines
                {
                    src_hdr->transl[dict][i] = -1;
                    continue;
                }
                src_hdr->transl[dict][i] = bcf_hdr_id2int(dst_hdr,dict,src_hdr->id[dict][i].key);
                if ( src_hdr->transl[dict][i]!=-1 && i!=src_hdr->transl[dict][i] ) src_hdr->ntransl++;
            }
        }
        if ( !src_hdr->ntransl )
        {
            free(src_hdr->transl[0]); src_hdr->transl[0] = NULL;
            free(src_hdr->transl[1]); src_hdr->transl[1] = NULL;
            src_hdr->ntransl = -1;
        }
        if ( src_hdr->ntransl==-1 ) return 0;
    }
    bcf_unpack(line,BCF_UN_ALL);

    // CHROM
    if ( src_hdr->transl[BCF_DT_CTG][line->rid] >=0 ) line->rid = src_hdr->transl[BCF_DT_CTG][line->rid];

    // FILTER
    for (i=0; i<line->d.n_flt; i++)
    {
        int src_id = line->d.flt[i];
        if ( src_hdr->transl[BCF_DT_ID][src_id] >=0 )
            line->d.flt[i] = src_hdr->transl[BCF_DT_ID][src_id];
        line->d.shared_dirty |= BCF1_DIRTY_FLT;
    }

    // INFO
    for (i=0; i<line->n_info; i++)
    {
        int src_id = line->d.info[i].key;
        int dst_id = src_hdr->transl[BCF_DT_ID][src_id];
        if ( dst_id<0 ) continue;
        line->d.info[i].key = dst_id;
        if ( !line->d.info[i].vptr ) continue;  // skip deleted
        int src_size = src_id>>7 ? ( src_id>>15 ? BCF_BT_INT32 : BCF_BT_INT16) : BCF_BT_INT8;
        int dst_size = dst_id>>7 ? ( dst_id>>15 ? BCF_BT_INT32 : BCF_BT_INT16) : BCF_BT_INT8;
        if ( src_size==dst_size )   // can overwrite
        {
            uint8_t *vptr = line->d.info[i].vptr - line->d.info[i].vptr_off;
            if ( dst_size==BCF_BT_INT8 ) { vptr[1] = (uint8_t)dst_id; }
            else if ( dst_size==BCF_BT_INT16 ) { *(uint16_t*)vptr = (uint16_t)dst_id; }
            else { *(uint32_t*)vptr = (uint32_t)dst_id; }
        }
        else    // must realloc
        {
            bcf_info_t *info = &line->d.info[i];
            kstring_t str = {0,0,0};
            bcf_enc_int1(&str, dst_id);
            bcf_enc_size(&str, info->len,info->type);
            uint32_t vptr_off = str.l;
            kputsn((char*)info->vptr, info->vptr_len, &str);
            if( info->vptr_free ) free(info->vptr - info->vptr_off);
            info->vptr_off = vptr_off;
            info->vptr = (uint8_t*)str.s + info->vptr_off;
            info->vptr_free = 1;
            line->d.shared_dirty |= BCF1_DIRTY_INF;
        }
    }

    // FORMAT
    for (i=0; i<line->n_fmt; i++)
    {
        int src_id = line->d.fmt[i].id;
        int dst_id = src_hdr->transl[BCF_DT_ID][src_id];
        if ( dst_id<0 ) continue;
        line->d.fmt[i].id = dst_id;
        if( !line->d.fmt[i].p ) continue;  // skip deleted
        int src_size = src_id>>7 ? ( src_id>>15 ? BCF_BT_INT32 : BCF_BT_INT16) : BCF_BT_INT8;
        int dst_size = dst_id>>7 ? ( dst_id>>15 ? BCF_BT_INT32 : BCF_BT_INT16) : BCF_BT_INT8;
        if ( src_size==dst_size )   // can overwrite
        {
            uint8_t *p = line->d.fmt[i].p - line->d.fmt[i].p_off;    // pointer to the vector size (4bits) and BT type (4bits)
            if ( dst_size==BCF_BT_INT8 ) { p[1] = dst_id; }
            else if ( dst_size==BCF_BT_INT16 ) { i16_to_le(dst_id, p + 1); }
            else { i32_to_le(dst_id, p + 1); }
        }
        else    // must realloc
        {
            bcf_fmt_t *fmt = &line->d.fmt[i];
            kstring_t str = {0,0,0};
            bcf_enc_int1(&str, dst_id);
            bcf_enc_size(&str, fmt->n, fmt->type);
            uint32_t p_off = str.l;
            kputsn((char*)fmt->p, fmt->p_len, &str);
            if( fmt->p_free ) free(fmt->p - fmt->p_off);
            fmt->p_off = p_off;
            fmt->p = (uint8_t*)str.s + fmt->p_off;
            fmt->p_free = 1;
            line->d.indiv_dirty = 1;
        }
    }
    return 0;
}


int vcf_format(const bcf_hdr_t *h, const bcf1_t *v, kstring_t *s)
{
    int i;
    int32_t max_dt_id = h->n[BCF_DT_ID];
    const char *chrom = bcf_seqname(h, v);
    if (!chrom) {
        hts_log_error("Invalid BCF, CONTIG id=%d not present in the header",
                      v->rid);
        errno = EINVAL;
        return -1;
    }
    bcf_unpack((bcf1_t*)v, BCF_UN_ALL);
    kputs(chrom, s); // CHROM
    kputc('\t', s); kputll(v->pos + 1, s); // POS
    kputc('\t', s); kputs(v->d.id ? v->d.id : ".", s); // ID
    kputc('\t', s); // REF
    if (v->n_allele > 0) kputs(v->d.allele[0], s);
    else kputc('.', s);
    kputc('\t', s); // ALT
    if (v->n_allele > 1) {
        for (i = 1; i < v->n_allele; ++i) {
            if (i > 1) kputc(',', s);
            kputs(v->d.allele[i], s);
        }
    } else kputc('.', s);
    kputc('\t', s); // QUAL
    if ( bcf_float_is_missing(v->qual) ) kputc('.', s); // QUAL
    else kputd(v->qual, s);
    kputc('\t', s); // FILTER
    if (v->d.n_flt) {
        for (i = 0; i < v->d.n_flt; ++i) {
            int32_t idx = v->d.flt[i];
            if (idx < 0 || idx >= max_dt_id
                || h->id[BCF_DT_ID][idx].key == NULL) {
                hts_log_error("Invalid BCF, the FILTER tag id=%d at %s:%"PRIhts_pos" not present in the header",
                              idx, bcf_seqname_safe(h, v), v->pos + 1);
                errno = EINVAL;
                return -1;
            }
            if (i) kputc(';', s);
            kputs(h->id[BCF_DT_ID][idx].key, s);
        }
    } else kputc('.', s);
    kputc('\t', s); // INFO
    if (v->n_info) {
        int first = 1;
        for (i = 0; i < v->n_info; ++i) {
            bcf_info_t *z = &v->d.info[i];
            if ( !z->vptr ) continue;
            if ( !first ) kputc(';', s);
            first = 0;
            if (z->key < 0 || z->key >= max_dt_id
                || h->id[BCF_DT_ID][z->key].key == NULL) {
                hts_log_error("Invalid BCF, the INFO tag id=%d is %s at %s:%"PRIhts_pos,
                              z->key,
                              z->key < 0 ? "negative"
                              : (z->key >= max_dt_id ? "too large" : "not present in the header"),
                              bcf_seqname_safe(h, v), v->pos+1);
                errno = EINVAL;
                return -1;
            }
            kputs(h->id[BCF_DT_ID][z->key].key, s);
            if (z->len <= 0) continue;
            kputc('=', s);
            if (z->len == 1)
            {
                switch (z->type)
                {
                    case BCF_BT_INT8:  if ( z->v1.i==bcf_int8_missing ) kputc('.', s); else kputw(z->v1.i, s); break;
                    case BCF_BT_INT16: if ( z->v1.i==bcf_int16_missing ) kputc('.', s); else kputw(z->v1.i, s); break;
                    case BCF_BT_INT32: if ( z->v1.i==bcf_int32_missing ) kputc('.', s); else kputw(z->v1.i, s); break;
                    case BCF_BT_INT64: if ( z->v1.i==bcf_int64_missing ) kputc('.', s); else kputll(z->v1.i, s); break;
                    case BCF_BT_FLOAT: if ( bcf_float_is_missing(z->v1.f) ) kputc('.', s); else kputd(z->v1.f, s); break;
                    case BCF_BT_CHAR:  kputc(z->v1.i, s); break;
                    default:
                        hts_log_error("Unexpected type %d at %s:%"PRIhts_pos, z->type, bcf_seqname_safe(h, v), v->pos+1);
                        errno = EINVAL;
                        return -1;
                }
            }
            else bcf_fmt_array(s, z->len, z->type, z->vptr);
        }
        if ( first ) kputc('.', s);
    } else kputc('.', s);
    // FORMAT and individual information
    if (v->n_sample)
    {
        int i,j;
        if ( v->n_fmt)
        {
            int gt_i = -1;
            bcf_fmt_t *fmt = v->d.fmt;
            int first = 1;
            for (i = 0; i < (int)v->n_fmt; ++i) {
                if ( !fmt[i].p ) continue;
                kputc(!first ? ':' : '\t', s); first = 0;
                if (fmt[i].id < 0 || fmt[i].id >= max_dt_id
                    || h->id[BCF_DT_ID][fmt[i].id].key == NULL) //!bcf_hdr_idinfo_exists(h,BCF_HL_FMT,fmt[i].id) )
                {
                    hts_log_error("Invalid BCF, the FORMAT tag id=%d at %s:%"PRIhts_pos" not present in the header", fmt[i].id, bcf_seqname_safe(h, v), v->pos+1);
                    errno = EINVAL;
                    return -1;
                }
                kputs(h->id[BCF_DT_ID][fmt[i].id].key, s);
                if (strcmp(h->id[BCF_DT_ID][fmt[i].id].key, "GT") == 0) gt_i = i;
            }
            if ( first ) kputs("\t.", s);
            for (j = 0; j < v->n_sample; ++j) {
                kputc('\t', s);
                first = 1;
                for (i = 0; i < (int)v->n_fmt; ++i) {
                    bcf_fmt_t *f = &fmt[i];
                    if ( !f->p ) continue;
                    if (!first) kputc(':', s);
                    first = 0;
                    if (gt_i == i)
                        bcf_format_gt(f,j,s);
                    else
                        bcf_fmt_array(s, f->n, f->type, f->p + j * (size_t)f->size);
                }
                if ( first ) kputc('.', s);
            }
        }
        else
            for (j=0; j<=v->n_sample; j++)
                kputs("\t.", s);
    }
    kputc('\n', s);
    return 0;
}


uint8_t *bcf_fmt_sized_array(kstring_t *s, uint8_t *ptr)
{
    int x, type;
    x = bcf_dec_size(ptr, &ptr, &type);
    bcf_fmt_array(s, x, type, ptr);
    return ptr + (x << bcf_type_shift[type]);
}


int bcf_remove_filter(const bcf_hdr_t *hdr, bcf1_t *line, int flt_id, int pass)
{
    if ( !(line->unpacked & BCF_UN_FLT) ) bcf_unpack(line, BCF_UN_FLT);
    int i;
    for (i=0; i<line->d.n_flt; i++)
        if ( flt_id==line->d.flt[i] ) break;
    if ( i==line->d.n_flt ) return 0;   // the filter is not present
    line->d.shared_dirty |= BCF1_DIRTY_FLT;
    if ( i!=line->d.n_flt-1 ) memmove(line->d.flt+i,line->d.flt+i+1,(line->d.n_flt-i-1)*sizeof(*line->d.flt));
    line->d.n_flt--;
    if ( !line->d.n_flt && pass ) bcf_add_filter(hdr,line,0);
    return 0;
}


void bcf_destroy(bcf1_t *v)
{
    if (!v) return;
    bcf_empty1(v);
    free(v);
}


int bcf_idx_init(htsFile *fp, bcf_hdr_t *h, int min_shift, const char *fnidx) {
    int n_lvls, nids = 0;

    if (fp->format.format == vcf)
        return vcf_idx_init(fp, h, min_shift, fnidx);

    if (!min_shift)
        min_shift = 14;

    n_lvls = idx_calc_n_lvls_ids(h, min_shift, 0, &nids);

    fp->idx = hts_idx_init(nids, HTS_FMT_CSI, bgzf_tell(fp->fp.bgzf), min_shift, n_lvls);
    if (!fp->idx) return -1;
    fp->fnidx = fnidx;

    return 0;
}


int bcf_hdr_id2int(const bcf_hdr_t *h, int which, const char *id)
{
    khint_t k;
    vdict_t *d = (vdict_t*)h->dict[which];
    k = kh_get(vdict, d, id);
    return k == kh_end(d)? -1 : kh_val(d, k).id;
}


static uint32_t avifCodecConfigurationBoxGetDepth(const avifCodecConfigurationBox * av1C)
{
    if (av1C->twelveBit) {
        return 12;
    } else if (av1C->highBitdepth) {
        return 10;
    }
    return 8;
}


static avifBool avifParseItemPropertyAssociation(avifMeta * meta, const uint8_t * raw, size_t rawLen)
{
    BEGIN_STREAM(s, raw, rawLen);

    uint8_t version;
    uint32_t flags;
    CHECK(avifROStreamReadVersionAndFlags(&s, &version, &flags));
    avifBool propertyIndexIsU16 = ((flags & 0x1) != 0);

    uint32_t entryCount;
    CHECK(avifROStreamReadU32(&s, &entryCount));
    for (uint32_t entryIndex = 0; entryIndex < entryCount; ++entryIndex) {
        unsigned int itemID;
        if (version < 1) {
            uint16_t tmp;
            CHECK(avifROStreamReadU16(&s, &tmp));
            itemID = tmp;
        } else {
            CHECK(avifROStreamReadU32(&s, &itemID));
        }
        uint8_t associationCount;
        CHECK(avifROStreamRead(&s, &associationCount, 1));
        for (uint8_t associationIndex = 0; associationIndex < associationCount; ++associationIndex) {
            avifBool essential = AVIF_FALSE;
            uint16_t propertyIndex = 0;
            if (propertyIndexIsU16) {
                CHECK(avifROStreamReadU16(&s, &propertyIndex));
                essential = ((propertyIndex & 0x8000) != 0);
                propertyIndex &= 0x7fff;
            } else {
                uint8_t tmp;
                CHECK(avifROStreamRead(&s, &tmp, 1));
                essential = ((tmp & 0x80) != 0);
                propertyIndex = tmp & 0x7f;
            }

            if (propertyIndex == 0) {
                // Not associated with any item
                continue;
            }
            --propertyIndex; // 1-indexed

            if (propertyIndex >= meta->properties.count) {
                return AVIF_FALSE;
            }

            avifDecoderItem * item = avifMetaFindItem(meta, itemID);
            if (!item) {
                return AVIF_FALSE;
            }

            // Copy property to item
            avifProperty * srcProp = &meta->properties.prop[propertyIndex];

            static const char * supportedTypes[] = { "ispe", "auxC", "colr", "av1C", "pasp", "clap", "irot", "imir", "pixi" };
            size_t supportedTypesCount = sizeof(supportedTypes) / sizeof(supportedTypes[0]);
            avifBool supportedType = AVIF_FALSE;
            for (size_t i = 0; i < supportedTypesCount; ++i) {
                if (!memcmp(srcProp->type, supportedTypes[i], 4)) {
                    supportedType = AVIF_TRUE;
                    break;
                }
            }
            if (supportedType) {
                avifProperty * dstProp = (avifProperty *)avifArrayPushPtr(&item->properties);
                memcpy(dstProp, srcProp, sizeof(avifProperty));
            } else {
                if (essential) {
                    // Discovered an essential item property that libavif doesn't support!
                    // Make a note to ignore this item later.
                    item->hasUnsupportedEssentialProperty = AVIF_TRUE;
                }
            }
        }
    }

    return AVIF_TRUE;
}


static avifTile * avifDecoderDataCreateTile(avifDecoderData * data)
{
    avifTile * tile = (avifTile *)avifArrayPushPtr(&data->tiles);
    tile->image = avifImageCreateEmpty();
    tile->input = avifCodecDecodeInputCreate();
    return tile;
}


avifBool avifDecoderIsKeyframe(const avifDecoder * decoder, uint32_t frameIndex)
{
    if ((decoder->data->tiles.count > 0) && decoder->data->tiles.tile[0].input) {
        if (frameIndex < decoder->data->tiles.tile[0].input->samples.count) {
            return decoder->data->tiles.tile[0].input->samples.sample[frameIndex].sync;
        }
    }
    return AVIF_FALSE;
}


static void avifMetaDestroy(avifMeta * meta)
{
    for (uint32_t i = 0; i < meta->items.count; ++i) {
        avifDecoderItem * item = &meta->items.item[i];
        avifArrayDestroy(&item->properties);
    }
    avifArrayDestroy(&meta->items);
    avifArrayDestroy(&meta->properties);
    avifArrayDestroy(&meta->idats);
    avifFree(meta);
}


static avifBool avifParseTimeToSampleBox(avifSampleTable * sampleTable, const uint8_t * raw, size_t rawLen)
{
    BEGIN_STREAM(s, raw, rawLen);

    CHECK(avifROStreamReadAndEnforceVersion(&s, 0));

    uint32_t entryCount;
    CHECK(avifROStreamReadU32(&s, &entryCount)); // unsigned int(32) entry_count;

    for (uint32_t i = 0; i < entryCount; ++i) {
        avifSampleTableTimeToSample * timeToSample = (avifSampleTableTimeToSample *)avifArrayPushPtr(&sampleTable->timeToSamples);
        CHECK(avifROStreamReadU32(&s, &timeToSample->sampleCount)); // unsigned int(32) sample_count;
        CHECK(avifROStreamReadU32(&s, &timeToSample->sampleDelta)); // unsigned int(32) sample_delta;
    }
    return AVIF_TRUE;
}


static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
			       sockptr_t optval, unsigned int optlen)
{
	struct sock *sk = sock->sk;
	int len, err = 0;
	struct bt_voice voice;
	u32 opt;
	struct bt_codecs *codecs;
	struct hci_dev *hdev;
	__u8 buffer[255];

	BT_DBG("sk %p", sk);

	lock_sock(sk);

	switch (optname) {

	case BT_DEFER_SETUP:
		if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
			err = -EINVAL;
			break;
		}

		if (copy_from_sockptr(&opt, optval, sizeof(u32))) {
			err = -EFAULT;
			break;
		}

		if (opt)
			set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
		else
			clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
		break;

	case BT_VOICE:
		if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND &&
		    sk->sk_state != BT_CONNECT2) {
			err = -EINVAL;
			break;
		}

		voice.setting = sco_pi(sk)->setting;

		len = min_t(unsigned int, sizeof(voice), optlen);
		if (copy_from_sockptr(&voice, optval, len)) {
			err = -EFAULT;
			break;
		}

		/* Explicitly check for these values */
		if (voice.setting != BT_VOICE_TRANSPARENT &&
		    voice.setting != BT_VOICE_CVSD_16BIT) {
			err = -EINVAL;
			break;
		}

		sco_pi(sk)->setting = voice.setting;
		hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src,
				     BDADDR_BREDR);
		if (!hdev) {
			err = -EBADFD;
			break;
		}
		if (enhanced_sco_capable(hdev) &&
		    voice.setting == BT_VOICE_TRANSPARENT)
			sco_pi(sk)->codec.id = BT_CODEC_TRANSPARENT;
		hci_dev_put(hdev);
		break;

	case BT_PKT_STATUS:
		if (copy_from_sockptr(&opt, optval, sizeof(u32))) {
			err = -EFAULT;
			break;
		}

		if (opt)
			sco_pi(sk)->cmsg_mask |= SCO_CMSG_PKT_STATUS;
		else
			sco_pi(sk)->cmsg_mask &= SCO_CMSG_PKT_STATUS;
		break;

	case BT_CODEC:
		if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND &&
		    sk->sk_state != BT_CONNECT2) {
			err = -EINVAL;
			break;
		}

		hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src,
				     BDADDR_BREDR);
		if (!hdev) {
			err = -EBADFD;
			break;
		}

		if (!hci_dev_test_flag(hdev, HCI_OFFLOAD_CODECS_ENABLED)) {
			hci_dev_put(hdev);
			err = -EOPNOTSUPP;
			break;
		}

		if (!hdev->get_data_path_id) {
			hci_dev_put(hdev);
			err = -EOPNOTSUPP;
			break;
		}

		if (optlen < sizeof(struct bt_codecs) ||
		    optlen > sizeof(buffer)) {
			hci_dev_put(hdev);
			err = -EINVAL;
			break;
		}

		if (copy_from_sockptr(buffer, optval, optlen)) {
			hci_dev_put(hdev);
			err = -EFAULT;
			break;
		}

		codecs = (void *)buffer;

		if (codecs->num_codecs > 1) {
			hci_dev_put(hdev);
			err = -EINVAL;
			break;
		}

		sco_pi(sk)->codec = codecs->codecs[0];
		hci_dev_put(hdev);
		break;

	default:
		err = -ENOPROTOOPT;
		break;
	}

	release_sock(sk);
	return err;
}


static void sco_sock_set_timer(struct sock *sk, long timeout)
{
	if (!sco_pi(sk)->conn)
		return;

	BT_DBG("sock %p state %d timeout %ld", sk, sk->sk_state, timeout);
	cancel_delayed_work(&sco_pi(sk)->conn->timeout_work);
	schedule_delayed_work(&sco_pi(sk)->conn->timeout_work, timeout);
}


static void sco_conn_ready(struct sco_conn *conn)
{
	struct sock *parent;
	struct sock *sk = conn->sk;

	BT_DBG("conn %p", conn);

	if (sk) {
		lock_sock(sk);
		sco_sock_clear_timer(sk);
		sk->sk_state = BT_CONNECTED;
		sk->sk_state_change(sk);
		release_sock(sk);
	} else {
		sco_conn_lock(conn);

		if (!conn->hcon) {
			sco_conn_unlock(conn);
			return;
		}

		parent = sco_get_sock_listen(&conn->hcon->src);
		if (!parent) {
			sco_conn_unlock(conn);
			return;
		}

		lock_sock(parent);

		sk = sco_sock_alloc(sock_net(parent), NULL,
				    BTPROTO_SCO, GFP_ATOMIC, 0);
		if (!sk) {
			release_sock(parent);
			sco_conn_unlock(conn);
			return;
		}

		sco_sock_init(sk, parent);

		bacpy(&sco_pi(sk)->src, &conn->hcon->src);
		bacpy(&sco_pi(sk)->dst, &conn->hcon->dst);

		hci_conn_hold(conn->hcon);
		__sco_chan_add(conn, sk, parent);

		if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags))
			sk->sk_state = BT_CONNECT2;
		else
			sk->sk_state = BT_CONNECTED;

		/* Wake up parent */
		parent->sk_data_ready(parent);

		release_sock(parent);

		sco_conn_unlock(conn);
	}
}


static void sco_sock_clear_timer(struct sock *sk)
{
	if (!sco_pi(sk)->conn)
		return;

	BT_DBG("sock %p state %d", sk, sk->sk_state);
	cancel_delayed_work(&sco_pi(sk)->conn->timeout_work);
}


build_authorize_challenge (CockpitAuth *self,
                           JsonObject *authorize,
                           GIOStream *connection,
                           GHashTable *headers,
                           JsonObject **body,
                           gchar **conversation)
{
  const gchar *challenge = NULL;
  gchar *type = NULL;
  JsonObject *object;
  GList *l, *names;

  if (!cockpit_json_get_string (authorize, "challenge", NULL, &challenge) ||
      !cockpit_authorize_type (challenge, &type))
    {
      g_message ("invalid \"challenge\" field in \"authorize\" message");
      return FALSE;
    }

  g_hash_table_replace (headers, g_strdup ("WWW-Authenticate"), g_strdup (challenge));
  *conversation = NULL;

  if (g_str_equal (type, "negotiate"))
    {
      gssapi_available = 1;
      *conversation = cockpit_auth_nonce (self);
      if (connection)
        g_object_set_data_full (G_OBJECT (connection), "negotiate", g_strdup (*conversation), g_free);
    }
  else if (g_str_equal (type, "x-conversation"))
    {
      cockpit_authorize_subject (challenge, conversation);
    }

  object = json_object_new ();
  names = json_object_get_members (authorize);
  for (l = names; l != NULL; l = g_list_next (l))
    {
      if (!g_str_equal (l->data, "challenge") && !g_str_equal (l->data, "cookie"))
        json_object_set_member (object, l->data, json_object_dup_member (authorize, l->data));
    }
  if (body)
    *body = object;

  g_list_free (names);
  g_free (type);
  return TRUE;
}


cockpit_auth_steal_authorization (GHashTable *headers,
                                  GIOStream *connection,
                                  gchar **ret_type,
                                  gchar **ret_conversation)
{
  char *type = NULL;
  gchar *ret = NULL;
  gchar *line;
  gpointer key;

  g_assert (headers != NULL);
  g_assert (ret_conversation != NULL);
  g_assert (ret_type != NULL);

  /* Avoid copying as it can contain passwords */
  if (g_hash_table_lookup_extended (headers, "Authorization", &key, (gpointer *)&line))
    {
      g_hash_table_steal (headers, "Authorization");
      g_free (key);

      /* This is being parsed heavily, enforce ASCII */
      if (!g_str_is_ascii (line))
        {
          g_message ("received invalid Authorize header, must be ASCII");
          goto out;
        }
    }
  else
    {
      /*
       * If we don't yet know that Negotiate authentication is possible
       * or not, then we ask our session to try to do Negotiate auth
       * but without any input data.
       */
      if (gssapi_available != 0)
        line = g_strdup ("Negotiate");
      else
        return NULL;
    }

  /* Dig out the authorization type */
  if (!cockpit_authorize_type (line, &type))
    goto out;

  /* If this is a conversation, get that part out too */
  if (g_str_equal (type, "x-conversation"))
    {
      if (!cockpit_authorize_subject (line, ret_conversation))
        goto out;
    }

  /*
   * So for negotiate authentication, conversation happens on a
   * single connection. Yes that's right, GSSAPI, NTLM, and all
   * those nice mechanisms are keep-alive based, not HTTP request based.
   */
  else if (g_str_equal (type, "negotiate"))
    {
      /* Resume an already running conversation? */
      if (ret_conversation && connection)
        *ret_conversation = g_strdup (g_object_get_data (G_OBJECT (connection), type));
    }

  if (ret_type)
    {
      *ret_type = type;
      type = NULL;
    }

  ret = line;
  line = NULL;

out:
  g_free (line);
  g_free (type);
  return ret;
}


cockpit_session_unref (gpointer data)
{
  CockpitSession *session = data;
  CockpitCreds *creds;
  GObject *object;

  session->refs--;
  if (session->refs > 0)
    return;

  cockpit_session_reset (data);

  g_free (session->name);
  g_free (session->cookie);

  if (session->authorize)
    json_object_unref (session->authorize);

  if (session->transport)
    {
      if (session->control_sig)
        g_signal_handler_disconnect (session->transport, session->control_sig);
      if (session->close_sig)
        g_signal_handler_disconnect (session->transport, session->close_sig);
      g_object_unref (session->transport);
    }

  if (session->service)
    {
      creds = cockpit_web_service_get_creds (session->service);
      object = G_OBJECT (session->service);
      session->service = NULL;
      if (creds)
        cockpit_creds_poison (creds);
      if (session->idling_sig)
        g_signal_handler_disconnect (object, session->idling_sig);
      if (session->destroy_sig)
        g_signal_handler_disconnect (object, session->destroy_sig);
      g_object_weak_unref (object, on_web_service_gone, session);
      g_object_run_dispose (object);
      g_object_unref (object);
    }

  if (session->timeout_tag)
    g_source_remove (session->timeout_tag);

  g_free (session);
}


cockpit_auth_init (CockpitAuth *self)
{
  static const gsize key_len = 128;
  gpointer key;

  key = cockpit_authorize_nonce (key_len);
  if (!key)
    g_error ("couldn't read random key, startup aborted");

  self->key = g_bytes_new_take (key, key_len);

  self->sessions = g_hash_table_new_full (g_str_hash, g_str_equal,
                                          NULL, cockpit_session_unref);

  self->conversations = g_hash_table_new_full (g_str_hash, g_str_equal,
                                               NULL, cockpit_session_unref);

  self->timeout_tag = g_timeout_add_seconds (get_process_idle (),
                                             on_process_timeout, self);

  self->startups = 0;
  self->max_startups = max_startups;
  self->max_startups_begin = max_startups;
  self->max_startups_rate = 100;
}


cockpit_auth_parse_application (const gchar *path,
                                gboolean *is_host)
{
  const gchar *pos;
  gchar *tmp = NULL;
  gchar *val = NULL;

  g_return_val_if_fail (path != NULL, NULL);
  g_return_val_if_fail (path[0] == '/', NULL);

  path += 1;

  /* We are being embedded as a specific application */
  if (g_str_has_prefix (path, "cockpit+") && path[8] != '\0')
    {
      pos = strchr (path, '/');
      if (pos)
        val = g_strndup (path, pos - path);
      else
        val =  g_strdup (path);
    }
  else if (path[0] == '=' && path[1] != '\0')
    {
      pos = strchr (path, '/');
      if (pos)
        {
          tmp = g_strndup (path, pos - path);
          val = g_strdup_printf ("cockpit+%s", tmp);
        }
      else
        {
          val = g_strdup_printf ("cockpit+%s", path);
        }

    }
  else
    {
      val = g_strdup ("cockpit");
    }

  if (is_host)
    *is_host = application_parse_host (val) != NULL;

  g_free (tmp);
  return val;
}


cockpit_auth_local_finish (CockpitAuth *self,
                           GAsyncResult *result,
                           GError **error)
{
  g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
                        cockpit_auth_local_async), FALSE);

  return g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
}


f2i(UINT8 *out_, const UINT8 *in_, int xsize) {
    int x;
    for (x = 0; x < xsize; x++, in_ += 4, out_ += 4) {
        FLOAT32 f;
        INT32 i;
        memcpy(&f, in_, sizeof(f));
        i = f;
        memcpy(out_, &i, sizeof(i));
    }
}


la2l(UINT8 *out, const UINT8 *in, int xsize) {
    int x;
    for (x = 0; x < xsize; x++, in += 4) {
        *out++ = in[0];
    }
}


bit2rgb(UINT8 *out, const UINT8 *in, int xsize) {
    int x;
    for (x = 0; x < xsize; x++) {
        UINT8 v = (*in++ != 0) ? 255 : 0;
        *out++ = v;
        *out++ = v;
        *out++ = v;
        *out++ = 255;
    }
}


ycbcr2la(UINT8 *out, const UINT8 *in, int xsize) {
    int x;
    for (x = 0; x < xsize; x++, in += 4, out += 4) {
        out[0] = out[1] = out[2] = in[0];
        out[3] = 255;
    }
}


p2la(UINT8 *out, const UINT8 *in, int xsize, const UINT8 *palette) {
    int x;
    /* FIXME: precalculate greyscale palette? */
    for (x = 0; x < xsize; x++, out += 4) {
        const UINT8 *rgba = &palette[*in++ * 4];
        out[0] = out[1] = out[2] = L(rgba) / 1000;
        out[3] = rgba[3];
    }
}


lA2la(UINT8 *out, const UINT8 *in, int xsize) {
    int x;
    unsigned int alpha, pixel, tmp;
    for (x = 0; x < xsize; x++, in += 4) {
        alpha = in[3];
        pixel = MULDIV255(in[0], alpha, tmp);
        *out++ = (UINT8)pixel;
        *out++ = (UINT8)pixel;
        *out++ = (UINT8)pixel;
        *out++ = (UINT8)alpha;
    }
}


rgb2hsv(UINT8 *out, const UINT8 *in, int xsize) {
    int x;
    for (x = 0; x < xsize; x++, in += 4, out += 4) {
        rgb2hsv_row(out, in);
        out[3] = in[3];
    }
}


topalette(
    Imaging imOut,
    Imaging imIn,
    const char *mode,
    ImagingPalette inpalette,
    int dither) {
    ImagingSectionCookie cookie;
    int alpha;
    int x, y;
    ImagingPalette palette = inpalette;
    ;

    /* Map L or RGB/RGBX/RGBA to palette image */
    if (strcmp(imIn->mode, "L") != 0 && strncmp(imIn->mode, "RGB", 3) != 0) {
        return (Imaging)ImagingError_ValueError("conversion not supported");
    }

    alpha = !strcmp(mode, "PA");

    if (palette == NULL) {
        /* FIXME: make user configurable */
        if (imIn->bands == 1) {
            palette = ImagingPaletteNew("RGB"); /* Initialised to grey ramp */
        } else {
            palette = ImagingPaletteNewBrowser(); /* Standard colour cube */
        }
    }

    if (!palette) {
        return (Imaging)ImagingError_ValueError("no palette");
    }

    imOut = ImagingNew2Dirty(mode, imOut, imIn);
    if (!imOut) {
        if (palette != inpalette) {
            ImagingPaletteDelete(palette);
        }
        return NULL;
    }

    ImagingPaletteDelete(imOut->palette);
    imOut->palette = ImagingPaletteDuplicate(palette);

    if (imIn->bands == 1) {
        /* greyscale image */

        /* Greyscale palette: copy data as is */
        ImagingSectionEnter(&cookie);
        for (y = 0; y < imIn->ysize; y++) {
            if (alpha) {
                l2la((UINT8 *)imOut->image[y], (UINT8 *)imIn->image[y], imIn->xsize);
            } else {
                memcpy(imOut->image[y], imIn->image[y], imIn->linesize);
            }
        }
        ImagingSectionLeave(&cookie);

    } else {
        /* colour image */

        /* Create mapping cache */
        if (ImagingPaletteCachePrepare(palette) < 0) {
            ImagingDelete(imOut);
            if (palette != inpalette) {
                ImagingPaletteDelete(palette);
            }
            return NULL;
        }

        if (dither) {
            /* floyd-steinberg dither */

            int *errors;
            errors = calloc(imIn->xsize + 1, sizeof(int) * 3);
            if (!errors) {
                ImagingDelete(imOut);
                return ImagingError_MemoryError();
            }

            /* Map each pixel to the nearest palette entry */
            ImagingSectionEnter(&cookie);
            for (y = 0; y < imIn->ysize; y++) {
                int r, r0, r1, r2;
                int g, g0, g1, g2;
                int b, b0, b1, b2;
                UINT8 *in = (UINT8 *)imIn->image[y];
                UINT8 *out = alpha ? (UINT8 *)imOut->image32[y] : imOut->image8[y];
                int *e = errors;

                r = r0 = r1 = 0;
                g = g0 = g1 = 0;
                b = b0 = b1 = b2 = 0;

                for (x = 0; x < imIn->xsize; x++, in += 4) {
                    int d2;
                    INT16 *cache;

                    r = CLIP8(in[0] + (r + e[3 + 0]) / 16);
                    g = CLIP8(in[1] + (g + e[3 + 1]) / 16);
                    b = CLIP8(in[2] + (b + e[3 + 2]) / 16);

                    /* get closest colour */
                    cache = &ImagingPaletteCache(palette, r, g, b);
                    if (cache[0] == 0x100) {
                        ImagingPaletteCacheUpdate(palette, r, g, b);
                    }
                    if (alpha) {
                        out[x * 4] = out[x * 4 + 1] = out[x * 4 + 2] = (UINT8)cache[0];
                        out[x * 4 + 3] = 255;
                    } else {
                        out[x] = (UINT8)cache[0];
                    }

                    r -= (int)palette->palette[cache[0] * 4];
                    g -= (int)palette->palette[cache[0] * 4 + 1];
                    b -= (int)palette->palette[cache[0] * 4 + 2];

                    /* propagate errors (don't ask ;-) */
                    r2 = r;
                    d2 = r + r;
                    r += d2;
                    e[0] = r + r0;
                    r += d2;
                    r0 = r + r1;
                    r1 = r2;
                    r += d2;
                    g2 = g;
                    d2 = g + g;
                    g += d2;
                    e[1] = g + g0;
                    g += d2;
                    g0 = g + g1;
                    g1 = g2;
                    g += d2;
                    b2 = b;
                    d2 = b + b;
                    b += d2;
                    e[2] = b + b0;
                    b += d2;
                    b0 = b + b1;
                    b1 = b2;
                    b += d2;

                    e += 3;
                }

                e[0] = b0;
                e[1] = b1;
                e[2] = b2;
            }
            ImagingSectionLeave(&cookie);
            free(errors);

        } else {
            /* closest colour */
            ImagingSectionEnter(&cookie);
            for (y = 0; y < imIn->ysize; y++) {
                int r, g, b;
                UINT8 *in = (UINT8 *)imIn->image[y];
                UINT8 *out = alpha ? (UINT8 *)imOut->image32[y] : imOut->image8[y];

                for (x = 0; x < imIn->xsize; x++, in += 4) {
                    INT16 *cache;

                    r = in[0];
                    g = in[1];
                    b = in[2];

                    /* get closest colour */
                    cache = &ImagingPaletteCache(palette, r, g, b);
                    if (cache[0] == 0x100) {
                        ImagingPaletteCacheUpdate(palette, r, g, b);
                    }
                    if (alpha) {
                        out[x * 4] = out[x * 4 + 1] = out[x * 4 + 2] = (UINT8)cache[0];
                        out[x * 4 + 3] = 255;
                    } else {
                        out[x] = (UINT8)cache[0];
                    }
                }
            }
            ImagingSectionLeave(&cookie);
        }
        if (inpalette != palette) {
            ImagingPaletteCacheDelete(palette);
        }
    }

    if (inpalette != palette) {
        ImagingPaletteDelete(palette);
    }

    return imOut;
}


I16L_F(UINT8 *out_, const UINT8 *in, int xsize) {
    int x;
    for (x = 0; x < xsize; x++, in += 2, out_ += 4) {
        FLOAT32 v = in[0] + ((int)in[1] << 8);
        memcpy(out_, &v, sizeof(v));
    }
}


h2_rx_data(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
{
	int w1 = 0, w2 = 0;
	char buf[4];
	unsigned wi;
	ssize_t cl;

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	ASSERT_RXTHR(h2);
	CHECK_OBJ_ORNULL(r2, H2_REQ_MAGIC);

	if (r2 == NULL || !r2->scheduled)
		return (0);
	if (r2->state >= H2_S_CLOS_REM) {
		r2->error = H2SE_STREAM_CLOSED;
		return (H2SE_STREAM_CLOSED); // rfc7540,l,1766,1769
	}
	Lck_Lock(&h2->sess->mtx);
	while (h2->mailcall != NULL && h2->error == 0 && r2->error == 0)
		AZ(Lck_CondWait(h2->cond, &h2->sess->mtx, 0));
	if (h2->error || r2->error) {
		Lck_Unlock(&h2->sess->mtx);
		return (h2->error ? h2->error : r2->error);
	}

	r2->reqbody_bytes += h2->rxf_len;
	if (h2->rxf_flags & H2FF_DATA_END_STREAM)
		r2->state = H2_S_CLOS_REM;
	cl = r2->req->htc->content_length;
	if (cl >= 0 && (r2->reqbody_bytes > cl ||
	      (r2->state >= H2_S_CLOS_REM && r2->reqbody_bytes != cl))) {
		VSLb(h2->vsl, SLT_Debug,
		    "H2: stream %u: Received data and Content-Length"
		    " mismatch", h2->rxf_stream);
		r2->error = H2SE_PROTOCOL_ERROR; // rfc7540,l,3150,3163
		if (r2->cond)
			AZ(pthread_cond_signal(r2->cond));
		Lck_Unlock(&h2->sess->mtx);
		return (H2SE_PROTOCOL_ERROR);
	}

	AZ(h2->mailcall);
	h2->mailcall = r2;
	h2->req0->r_window -= h2->rxf_len;
	r2->r_window -= h2->rxf_len;
	// req_bodybytes accounted in CNT code.
	if (r2->cond)
		AZ(pthread_cond_signal(r2->cond));
	while (h2->mailcall != NULL && h2->error == 0 && r2->error == 0)
		AZ(Lck_CondWait(h2->cond, &h2->sess->mtx, 0));
	wi = cache_param->h2_rx_window_increment;
	if (h2->req0->r_window < cache_param->h2_rx_window_low_water) {
		h2->req0->r_window += wi;
		w1 = 1;
	}
	if (r2->r_window < cache_param->h2_rx_window_low_water) {
		r2->r_window += wi;
		w2 = 1;
	}

	Lck_Unlock(&h2->sess->mtx);

	if (w1 || w2) {
		vbe32enc(buf, wi);
		H2_Send_Get(wrk, h2, h2->req0);
		if (w1)
			H2_Send_Frame(wrk, h2, H2_F_WINDOW_UPDATE, 0,
			    4, 0, buf);
		if (w2)
			H2_Send_Frame(wrk, h2, H2_F_WINDOW_UPDATE, 0,
			    4, r2->stream, buf);
		H2_Send_Rel(h2, h2->req0);
	}
	return (0);
}


h2_req_body(struct req *req)
{
	struct h2_req *r2;
	struct vfp_entry *vfe;

	CHECK_OBJ(req, REQ_MAGIC);
	CAST_OBJ_NOTNULL(r2, req->transport_priv, H2_REQ_MAGIC);
	vfe = VFP_Push(req->vfc, &h2_body);
	AN(vfe);
	vfe->priv1 = r2;
}


h2_rxframe(struct worker *wrk, struct h2_sess *h2)
{
	enum htc_status_e hs;
	h2_frame h2f;
	h2_error h2e;
	char b[8];

	ASSERT_RXTHR(h2);
	VTCP_blocking(*h2->htc->rfd);
	h2->sess->t_idle = VTIM_real();
	hs = HTC_RxStuff(h2->htc, h2_frame_complete,
	    NULL, NULL, NAN,
	    h2->sess->t_idle + SESS_TMO(h2->sess, timeout_idle),
	    NAN, h2->local_settings.max_frame_size + 9);
	switch (hs) {
	case HTC_S_COMPLETE:
		break;
	case HTC_S_TIMEOUT:
		if (h2_sweep(wrk, h2))
			return (1);

		/* FALLTHROUGH */
	default:
		/* XXX: HTC_S_OVERFLOW / FRAME_SIZE_ERROR handling */
		Lck_Lock(&h2->sess->mtx);
		VSLb(h2->vsl, SLT_Debug, "H2: No frame (hs=%d)", hs);
		h2->error = H2CE_NO_ERROR;
		Lck_Unlock(&h2->sess->mtx);
		return (0);
	}

	if (h2->do_sweep)
		(void)h2_sweep(wrk, h2);

	h2->rxf_len =  vbe32dec(h2->htc->rxbuf_b) >> 8;
	h2->rxf_type =  h2->htc->rxbuf_b[3];
	h2->rxf_flags = h2->htc->rxbuf_b[4];
	h2->rxf_stream = vbe32dec(h2->htc->rxbuf_b + 5);
	h2->rxf_stream &= ~(1LU<<31);			// rfc7540,l,690,692
	h2->rxf_data = (void*)(h2->htc->rxbuf_b + 9);
	/* XXX: later full DATA will not be rx'ed yet. */
	HTC_RxPipeline(h2->htc, h2->htc->rxbuf_b + h2->rxf_len + 9);

	h2_vsl_frame(h2, h2->htc->rxbuf_b, 9L + h2->rxf_len);
	h2->srq->acct.req_hdrbytes += 9;

	if (h2->rxf_type >= H2FMAX) {
		// rfc7540,l,679,681
		// XXX: later, drain rest of frame
		h2->bogosity++;
		Lck_Lock(&h2->sess->mtx);
		VSLb(h2->vsl, SLT_Debug,
		    "H2: Unknown frame type 0x%02x (ignored)",
		    (uint8_t)h2->rxf_type);
		Lck_Unlock(&h2->sess->mtx);
		h2->srq->acct.req_bodybytes += h2->rxf_len;
		return (1);
	}
	h2f = h2flist[h2->rxf_type];

	AN(h2f->name);
	AN(h2f->rxfunc);
	if (h2f->overhead)
		h2->srq->acct.req_bodybytes += h2->rxf_len;

	if (h2->rxf_flags & ~h2f->flags) {
		// rfc7540,l,687,688
		h2->bogosity++;
		Lck_Lock(&h2->sess->mtx);
		VSLb(h2->vsl, SLT_Debug,
		    "H2: Unknown flags 0x%02x on %s (ignored)",
		    (uint8_t)h2->rxf_flags & ~h2f->flags, h2f->name);
		Lck_Unlock(&h2->sess->mtx);
		h2->rxf_flags &= h2f->flags;
	}

	h2e = h2_procframe(wrk, h2, h2f);
	if (h2->error == 0 && h2e) {
		h2->error = h2e;
		vbe32enc(b, h2->highest_stream);
		vbe32enc(b + 4, h2e->val);
		H2_Send_Get(wrk, h2, h2->req0);
		H2_Send_Frame(wrk, h2, H2_F_GOAWAY, 0, 8, 0, b);
		H2_Send_Rel(h2, h2->req0);
	}
	return (h2->error ? 0 : 1);
}


h2_framename(enum h2frame h2f)
{

	switch (h2f) {
#define H2_FRAME(l,u,t,f,...)	case H2F_##u: return #u;
#include "tbl/h2_frames.h"
	default:
		return (NULL);
	}
}


crypt_pw_md5_enc(const char *pwd)
{
    return crypt_pw_enc_by_hash(pwd, CRYPT_MD5);
}


static int cr8_write_interception(struct kvm_vcpu *vcpu)
{
	int r;

	u8 cr8_prev = kvm_get_cr8(vcpu);
	/* instruction emulation calls kvm_set_cr8() */
	r = cr_interception(vcpu);
	if (lapic_in_kernel(vcpu))
		return r;
	if (cr8_prev <= kvm_get_cr8(vcpu))
		return r;
	vcpu->run->exit_reason = KVM_EXIT_SET_TPR;
	return 0;
}


void nested_sync_control_from_vmcb02(struct vcpu_svm *svm)
{
	u32 mask;
	svm->nested.ctl.event_inj      = svm->vmcb->control.event_inj;
	svm->nested.ctl.event_inj_err  = svm->vmcb->control.event_inj_err;

	/* Only a few fields of int_ctl are written by the processor.  */
	mask = V_IRQ_MASK | V_TPR_MASK;
	if (!(svm->nested.ctl.int_ctl & V_INTR_MASKING_MASK) &&
	    svm_is_intercept(svm, INTERCEPT_VINTR)) {
		/*
		 * In order to request an interrupt window, L0 is usurping
		 * svm->vmcb->control.int_ctl and possibly setting V_IRQ
		 * even if it was clear in L1's VMCB.  Restoring it would be
		 * wrong.  However, in this case V_IRQ will remain true until
		 * interrupt_window_interception calls svm_clear_vintr and
		 * restores int_ctl.  We can just leave it aside.
		 */
		mask &= ~V_IRQ_MASK;
	}
	svm->nested.ctl.int_ctl        &= ~mask;
	svm->nested.ctl.int_ctl        |= svm->vmcb->control.int_ctl & mask;
}


static int pause_interception(struct kvm_vcpu *vcpu)
{
	bool in_kernel;

	/*
	 * CPL is not made available for an SEV-ES guest, therefore
	 * vcpu->arch.preempted_in_kernel can never be true.  Just
	 * set in_kernel to false as well.
	 */
	in_kernel = !sev_es_guest(vcpu->kvm) && svm_get_cpl(vcpu) == 0;

	if (!kvm_pause_in_guest(vcpu->kvm))
		grow_ple_window(vcpu);

	kvm_vcpu_on_spin(vcpu, in_kernel);
	return kvm_skip_emulated_instruction(vcpu);
}


static int npf_interception(struct kvm_vcpu *vcpu)
{
	struct vcpu_svm *svm = to_svm(vcpu);

	u64 fault_address = svm->vmcb->control.exit_info_2;
	u64 error_code = svm->vmcb->control.exit_info_1;

	trace_kvm_page_fault(fault_address, error_code);
	return kvm_mmu_page_fault(vcpu, fault_address, error_code,
			static_cpu_has(X86_FEATURE_DECODEASSISTS) ?
			svm->vmcb->control.insn_bytes : NULL,
			svm->vmcb->control.insn_len);
}


static void svm_disable_lbrv(struct kvm_vcpu *vcpu)
{
	struct vcpu_svm *svm = to_svm(vcpu);

	svm->vmcb->control.virt_ext &= ~LBR_CTL_ENABLE_MASK;
	set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTBRANCHFROMIP, 0, 0);
	set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTBRANCHTOIP, 0, 0);
	set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTINTFROMIP, 0, 0);
	set_msr_interception(vcpu, svm->msrpm, MSR_IA32_LASTINTTOIP, 0, 0);
}


static bool check_selective_cr0_intercepted(struct kvm_vcpu *vcpu,
					    unsigned long val)
{
	struct vcpu_svm *svm = to_svm(vcpu);
	unsigned long cr0 = vcpu->arch.cr0;
	bool ret = false;

	if (!is_guest_mode(vcpu) ||
	    (!(vmcb_is_intercept(&svm->nested.ctl, INTERCEPT_SELECTIVE_CR0))))
		return false;

	cr0 &= ~SVM_CR0_SELECTIVE_MASK;
	val &= ~SVM_CR0_SELECTIVE_MASK;

	if (cr0 ^ val) {
		svm->vmcb->control.exit_code = SVM_EXIT_CR0_SEL_WRITE;
		ret = (nested_svm_exit_handled(svm) == NESTED_EXIT_DONE);
	}

	return ret;
}


static int nested_svm_load_cr3(struct kvm_vcpu *vcpu, unsigned long cr3,
			       bool nested_npt, bool reload_pdptrs)
{
	if (CC(kvm_vcpu_is_illegal_gpa(vcpu, cr3)))
		return -EINVAL;

	if (reload_pdptrs && !nested_npt && is_pae_paging(vcpu) &&
	    CC(!load_pdptrs(vcpu, vcpu->arch.walk_mmu, cr3)))
		return -EINVAL;

	if (!nested_npt)
		kvm_mmu_new_pgd(vcpu, cr3);

	vcpu->arch.cr3 = cr3;
	kvm_register_mark_available(vcpu, VCPU_EXREG_CR3);

	/* Re-initialize the MMU, e.g. to pick up CR4 MMU role changes. */
	kvm_init_mmu(vcpu);

	return 0;
}


void svm_leave_nested(struct vcpu_svm *svm)
{
	struct kvm_vcpu *vcpu = &svm->vcpu;

	if (is_guest_mode(vcpu)) {
		svm->nested.nested_run_pending = 0;
		svm->nested.vmcb12_gpa = INVALID_GPA;

		leave_guest_mode(vcpu);

		svm_switch_vmcb(svm, &svm->vmcb01);

		nested_svm_uninit_mmu_context(vcpu);
		vmcb_mark_all_dirty(svm->vmcb);
	}

	kvm_clear_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu);
}


static int pf_interception(struct kvm_vcpu *vcpu)
{
	struct vcpu_svm *svm = to_svm(vcpu);

	u64 fault_address = svm->vmcb->control.exit_info_2;
	u64 error_code = svm->vmcb->control.exit_info_1;

	return kvm_handle_page_fault(vcpu, error_code, fault_address,
			static_cpu_has(X86_FEATURE_DECODEASSISTS) ?
			svm->vmcb->control.insn_bytes : NULL,
			svm->vmcb->control.insn_len);
}


static void svm_update_exception_bitmap(struct kvm_vcpu *vcpu)
{
	struct vcpu_svm *svm = to_svm(vcpu);

	clr_exception_intercept(svm, BP_VECTOR);

	if (vcpu->guest_debug & KVM_GUESTDBG_ENABLE) {
		if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP)
			set_exception_intercept(svm, BP_VECTOR);
	}
}


static int svm_nmi_allowed(struct kvm_vcpu *vcpu, bool for_injection)
{
	struct vcpu_svm *svm = to_svm(vcpu);
	if (svm->nested.nested_run_pending)
		return -EBUSY;

	/* An NMI must not be injected into L2 if it's supposed to VM-Exit.  */
	if (for_injection && is_guest_mode(vcpu) && nested_exit_on_nmi(svm))
		return -EBUSY;

	return !svm_nmi_blocked(vcpu);
}


static __init void svm_set_cpu_caps(void)
{
	kvm_set_cpu_caps();

	supported_xss = 0;

	/* CPUID 0x80000001 and 0x8000000A (SVM features) */
	if (nested) {
		kvm_cpu_cap_set(X86_FEATURE_SVM);

		if (nrips)
			kvm_cpu_cap_set(X86_FEATURE_NRIPS);

		if (npt_enabled)
			kvm_cpu_cap_set(X86_FEATURE_NPT);

		/* Nested VM can receive #VMEXIT instead of triggering #GP */
		kvm_cpu_cap_set(X86_FEATURE_SVME_ADDR_CHK);
	}

	/* CPUID 0x80000008 */
	if (boot_cpu_has(X86_FEATURE_LS_CFG_SSBD) ||
	    boot_cpu_has(X86_FEATURE_AMD_SSBD))
		kvm_cpu_cap_set(X86_FEATURE_VIRT_SSBD);

	/* CPUID 0x8000001F (SME/SEV features) */
	sev_set_cpu_caps();
}


static void svm_enable_irq_window(struct kvm_vcpu *vcpu)
{
	struct vcpu_svm *svm = to_svm(vcpu);

	/*
	 * In case GIF=0 we can't rely on the CPU to tell us when GIF becomes
	 * 1, because that's a separate STGI/VMRUN intercept.  The next time we
	 * get that intercept, this function will be called again though and
	 * we'll get the vintr intercept. However, if the vGIF feature is
	 * enabled, the STGI interception will not occur. Enable the irq
	 * window under the assumption that the hardware will set the GIF.
	 */
	if (vgif_enabled(svm) || gif_set(svm)) {
		/*
		 * IRQ window is not needed when AVIC is enabled,
		 * unless we have pending ExtINT since it cannot be injected
		 * via AVIC. In such case, we need to temporarily disable AVIC,
		 * and fallback to injecting IRQ via V_IRQ.
		 */
		svm_toggle_avic_for_irq_window(vcpu, false);
		svm_set_vintr(svm);
	}
}


static int mc_interception(struct kvm_vcpu *vcpu)
{
	return 1;
}


static struct vmcb_seg *svm_seg(struct kvm_vcpu *vcpu, int seg)
{
	struct vmcb_save_area *save = &to_svm(vcpu)->vmcb->save;
	struct vmcb_save_area *save01 = &to_svm(vcpu)->vmcb01.ptr->save;

	switch (seg) {
	case VCPU_SREG_CS: return &save->cs;
	case VCPU_SREG_DS: return &save->ds;
	case VCPU_SREG_ES: return &save->es;
	case VCPU_SREG_FS: return &save01->fs;
	case VCPU_SREG_GS: return &save01->gs;
	case VCPU_SREG_SS: return &save->ss;
	case VCPU_SREG_TR: return &save01->tr;
	case VCPU_SREG_LDTR: return &save01->ldtr;
	}
	BUG();
	return NULL;
}


static void svm_get_exit_info(struct kvm_vcpu *vcpu, u64 *info1, u64 *info2,
			      u32 *intr_info, u32 *error_code)
{
	struct vmcb_control_area *control = &to_svm(vcpu)->vmcb->control;

	*info1 = control->exit_info_1;
	*info2 = control->exit_info_2;
	*intr_info = control->exit_int_info;
	if ((*intr_info & SVM_EXITINTINFO_VALID) &&
	    (*intr_info & SVM_EXITINTINFO_VALID_ERR))
		*error_code = control->exit_int_info_err;
	else
		*error_code = 0;
}


static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
{
	struct vcpu_svm *svm = to_svm(vcpu);

	switch (msr_info->index) {
	case MSR_STAR:
		msr_info->data = svm->vmcb01.ptr->save.star;
		break;
#ifdef CONFIG_X86_64
	case MSR_LSTAR:
		msr_info->data = svm->vmcb01.ptr->save.lstar;
		break;
	case MSR_CSTAR:
		msr_info->data = svm->vmcb01.ptr->save.cstar;
		break;
	case MSR_KERNEL_GS_BASE:
		msr_info->data = svm->vmcb01.ptr->save.kernel_gs_base;
		break;
	case MSR_SYSCALL_MASK:
		msr_info->data = svm->vmcb01.ptr->save.sfmask;
		break;
#endif
	case MSR_IA32_SYSENTER_CS:
		msr_info->data = svm->vmcb01.ptr->save.sysenter_cs;
		break;
	case MSR_IA32_SYSENTER_EIP:
		msr_info->data = (u32)svm->vmcb01.ptr->save.sysenter_eip;
		if (guest_cpuid_is_intel(vcpu))
			msr_info->data |= (u64)svm->sysenter_eip_hi << 32;
		break;
	case MSR_IA32_SYSENTER_ESP:
		msr_info->data = svm->vmcb01.ptr->save.sysenter_esp;
		if (guest_cpuid_is_intel(vcpu))
			msr_info->data |= (u64)svm->sysenter_esp_hi << 32;
		break;
	case MSR_TSC_AUX:
		msr_info->data = svm->tsc_aux;
		break;
	/*
	 * Nobody will change the following 5 values in the VMCB so we can
	 * safely return them on rdmsr. They will always be 0 until LBRV is
	 * implemented.
	 */
	case MSR_IA32_DEBUGCTLMSR:
		msr_info->data = svm->vmcb->save.dbgctl;
		break;
	case MSR_IA32_LASTBRANCHFROMIP:
		msr_info->data = svm->vmcb->save.br_from;
		break;
	case MSR_IA32_LASTBRANCHTOIP:
		msr_info->data = svm->vmcb->save.br_to;
		break;
	case MSR_IA32_LASTINTFROMIP:
		msr_info->data = svm->vmcb->save.last_excp_from;
		break;
	case MSR_IA32_LASTINTTOIP:
		msr_info->data = svm->vmcb->save.last_excp_to;
		break;
	case MSR_VM_HSAVE_PA:
		msr_info->data = svm->nested.hsave_msr;
		break;
	case MSR_VM_CR:
		msr_info->data = svm->nested.vm_cr_msr;
		break;
	case MSR_IA32_SPEC_CTRL:
		if (!msr_info->host_initiated &&
		    !guest_has_spec_ctrl_msr(vcpu))
			return 1;

		if (boot_cpu_has(X86_FEATURE_V_SPEC_CTRL))
			msr_info->data = svm->vmcb->save.spec_ctrl;
		else
			msr_info->data = svm->spec_ctrl;
		break;
	case MSR_AMD64_VIRT_SPEC_CTRL:
		if (!msr_info->host_initiated &&
		    !guest_cpuid_has(vcpu, X86_FEATURE_VIRT_SSBD))
			return 1;

		msr_info->data = svm->virt_spec_ctrl;
		break;
	case MSR_F15H_IC_CFG: {

		int family, model;

		family = guest_cpuid_family(vcpu);
		model  = guest_cpuid_model(vcpu);

		if (family < 0 || model < 0)
			return kvm_get_msr_common(vcpu, msr_info);

		msr_info->data = 0;

		if (family == 0x15 &&
		    (model >= 0x2 && model < 0x20))
			msr_info->data = 0x1E;
		}
		break;
	case MSR_F10H_DECFG:
		msr_info->data = svm->msr_decfg;
		break;
	default:
		return kvm_get_msr_common(vcpu, msr_info);
	}
	return 0;
}


void svm_copy_vmloadsave_state(struct vmcb *to_vmcb, struct vmcb *from_vmcb)
{
	to_vmcb->save.fs = from_vmcb->save.fs;
	to_vmcb->save.gs = from_vmcb->save.gs;
	to_vmcb->save.tr = from_vmcb->save.tr;
	to_vmcb->save.ldtr = from_vmcb->save.ldtr;
	to_vmcb->save.kernel_gs_base = from_vmcb->save.kernel_gs_base;
	to_vmcb->save.star = from_vmcb->save.star;
	to_vmcb->save.lstar = from_vmcb->save.lstar;
	to_vmcb->save.cstar = from_vmcb->save.cstar;
	to_vmcb->save.sfmask = from_vmcb->save.sfmask;
	to_vmcb->save.sysenter_cs = from_vmcb->save.sysenter_cs;
	to_vmcb->save.sysenter_esp = from_vmcb->save.sysenter_esp;
	to_vmcb->save.sysenter_eip = from_vmcb->save.sysenter_eip;
}


static void svm_set_dr7(struct kvm_vcpu *vcpu, unsigned long value)
{
	struct vcpu_svm *svm = to_svm(vcpu);

	if (vcpu->arch.guest_state_protected)
		return;

	svm->vmcb->save.dr7 = value;
	vmcb_mark_dirty(svm->vmcb, VMCB_DR);
}


_cairo_image_surface_create_from_jpeg (GInputStream  *istream,
				       GthFileData   *file_data,
				       int            requested_size,
				       int           *original_width_p,
				       int           *original_height_p,
				       gboolean      *loaded_original_p,
				       gpointer       user_data,
				       GCancellable  *cancellable,
				       GError       **error)
{
	GthImage                      *image;
	JpegInfoFlags		       info_flags;
	gboolean                       load_scaled;
	GthTransform                   orientation;
	int                            output_width;
	int                            output_height;
	int                            destination_width;
	int                            destination_height;
	int                            line_start;
	int                            line_step;
	int                            pixel_step;
	void                          *in_buffer;
	gsize                          in_buffer_size;
	JpegInfoData                   jpeg_info;
	struct error_handler_data      jsrcerr;
	struct jpeg_decompress_struct  srcinfo;
	cairo_surface_t               *surface;
	cairo_surface_metadata_t      *metadata;
	unsigned char                 *surface_data;
	unsigned char                 *surface_row;
	JSAMPARRAY                     buffer;
	int                            buffer_stride;
	int                            scanned_lines;
	JDIMENSION                     n_lines;
	JSAMPARRAY                     buffer_row;
	int                            l;
	unsigned char                 *p_surface;
	guchar                         r, g, b;
	guint32                        pixel;
	unsigned char                 *p_buffer;
	int                            x;
	gboolean                       read_all_scanlines = FALSE;
	volatile gboolean                       finished = FALSE;

	image = gth_image_new ();
	surface = NULL;

	if (! _g_input_stream_read_all (istream,
			      	        &in_buffer,
			      	        &in_buffer_size,
			      	        cancellable,
			      	        error))
	{
		return image;
	}

	_jpeg_info_data_init (&jpeg_info);
	info_flags = _JPEG_INFO_EXIF_ORIENTATION;
#if HAVE_LCMS2
	info_flags |= _JPEG_INFO_EXIF_COLOR_SPACE | _JPEG_INFO_ICC_PROFILE;
#endif
	_jpeg_info_get_from_buffer (in_buffer, in_buffer_size, info_flags, &jpeg_info);
	if (jpeg_info.valid & _JPEG_INFO_EXIF_ORIENTATION)
		orientation = jpeg_info.orientation;
	else
		orientation = GTH_TRANSFORM_NONE;
#if HAVE_LCMS2
	{
		GthICCProfile *profile = NULL;

		if (jpeg_info.valid & _JPEG_INFO_ICC_PROFILE) {
			profile = gth_icc_profile_new (GTH_ICC_PROFILE_ID_UNKNOWN, cmsOpenProfileFromMem (jpeg_info.icc_data, jpeg_info.icc_data_size));
		}
		else if (jpeg_info.valid & _JPEG_INFO_EXIF_COLOR_SPACE) {
			if (jpeg_info.color_space == GTH_COLOR_SPACE_SRGB)
				profile = gth_icc_profile_new_srgb ();
		}

		if (profile != NULL) {
			gth_image_set_icc_profile (image, profile);
			g_object_unref (profile);
		}
	}
#endif
	_jpeg_info_data_dispose (&jpeg_info);

	srcinfo.err = jpeg_std_error (&(jsrcerr.pub));
	jsrcerr.pub.error_exit = fatal_error_handler;
	jsrcerr.pub.output_message = output_message_handler;
	jsrcerr.error = error;

	jpeg_create_decompress (&srcinfo);

	if (sigsetjmp (jsrcerr.setjmp_buffer, 1))
		goto stop_loading;

	_jpeg_memory_src (&srcinfo, in_buffer, in_buffer_size);

	jpeg_read_header (&srcinfo, TRUE);

	srcinfo.out_color_space = srcinfo.jpeg_color_space; /* make all the color space conversions manually */

	load_scaled = (requested_size > 0) && (requested_size < srcinfo.image_width) && (requested_size < srcinfo.image_height);
	if (load_scaled) {
		for (srcinfo.scale_denom = 1; srcinfo.scale_denom <= 16; srcinfo.scale_denom++) {
			jpeg_calc_output_dimensions (&srcinfo);
			if ((srcinfo.output_width < requested_size) || (srcinfo.output_height < requested_size)) {
				srcinfo.scale_denom -= 1;
				break;
			}
		}

		if (srcinfo.scale_denom <= 0) {
			srcinfo.scale_denom = srcinfo.scale_num;
			load_scaled = FALSE;
		}
	}

	jpeg_calc_output_dimensions (&srcinfo);

	buffer_stride = srcinfo.output_width * srcinfo.output_components;
	buffer = (*srcinfo.mem->alloc_sarray) ((j_common_ptr) &srcinfo, JPOOL_IMAGE, buffer_stride, srcinfo.rec_outbuf_height);

	jpeg_start_decompress (&srcinfo);

	output_width = MIN (srcinfo.output_width, CAIRO_MAX_IMAGE_SIZE);
	output_height = MIN (srcinfo.output_height, CAIRO_MAX_IMAGE_SIZE);
	_cairo_image_surface_transform_get_steps (CAIRO_FORMAT_ARGB32,
						  output_width,
						  output_height,
						  orientation,
						  &destination_width,
						  &destination_height,
						  &line_start,
						  &line_step,
						  &pixel_step);

#if 0
	g_print ("requested: %d, original [%d, %d] ==> load at [%d, %d]\n",
			requested_size,
			srcinfo.image_width,
			srcinfo.image_height,
			destination_width,
			destination_height);
#endif

	surface = _cairo_image_surface_create (CAIRO_FORMAT_ARGB32, destination_width, destination_height);
	if (surface == NULL) {
		jpeg_destroy_decompress (&srcinfo);
		g_free (in_buffer);

		return image;
	}

	metadata = _cairo_image_surface_get_metadata (surface);
	_cairo_metadata_set_has_alpha (metadata, FALSE);
	surface_data = _cairo_image_surface_flush_and_get_data (surface);
	surface_row = surface_data + line_start;
	scanned_lines = 0;

	switch (srcinfo.out_color_space) {
	case JCS_CMYK:
		{
			register unsigned char *cmyk_tab;
			int c, m, y, k, ki;

			CMYK_table_init ();
			cmyk_tab = CMYK_Tab;

			while (srcinfo.output_scanline < output_height) {
				if (g_cancellable_is_cancelled (cancellable))
					goto stop_loading;

				n_lines = jpeg_read_scanlines (&srcinfo, buffer, srcinfo.rec_outbuf_height);
				if (scanned_lines + n_lines > output_height)
					n_lines = output_height - scanned_lines;

				buffer_row = buffer;
				for (l = 0; l < n_lines; l++) {
					p_surface = surface_row;
					p_buffer = buffer_row[l];

					if (g_cancellable_is_cancelled (cancellable))
						goto stop_loading;

					for (x = 0; x < output_width; x++) {
						if (srcinfo.saw_Adobe_marker) {
							c = p_buffer[0];
							m = p_buffer[1];
							y = p_buffer[2];
							k = p_buffer[3];
						}
						else {
							c = 255 - p_buffer[0];
							m = 255 - p_buffer[1];
							y = 255 - p_buffer[2];
							k = 255 - p_buffer[3];
						}

						ki = k << 8; /* ki = k * 256 */
						r = cmyk_tab[ki + c];
						g = cmyk_tab[ki + m];
						b = cmyk_tab[ki + y];
						pixel = CAIRO_RGBA_TO_UINT32 (r, g, b, 0xff);
						memcpy (p_surface, &pixel, sizeof (guint32));

						p_surface += pixel_step;
						p_buffer += 4 /*srcinfo.output_components*/;
					}

					surface_row += line_step;
					buffer_row += buffer_stride;
					scanned_lines += 1;
				}
			}
		}
		break;

	case JCS_GRAYSCALE:
		{
			while (srcinfo.output_scanline < output_height) {
				if (g_cancellable_is_cancelled (cancellable))
					goto stop_loading;

				n_lines = jpeg_read_scanlines (&srcinfo, buffer, srcinfo.rec_outbuf_height);
				if (scanned_lines + n_lines > output_height)
					n_lines = output_height - scanned_lines;

				buffer_row = buffer;
				for (l = 0; l < n_lines; l++) {
					p_surface = surface_row;
					p_buffer = buffer_row[l];

					if (g_cancellable_is_cancelled (cancellable))
						goto stop_loading;

					for (x = 0; x < output_width; x++) {
						r = g = b = p_buffer[0];
						pixel = CAIRO_RGBA_TO_UINT32 (r, g, b, 0xff);
						memcpy (p_surface, &pixel, sizeof (guint32));

						p_surface += pixel_step;
						p_buffer += 1 /*srcinfo.output_components*/;
					}

					surface_row += line_step;
					buffer_row += buffer_stride;
					scanned_lines += 1;
				}
			}
		}
		break;

	case JCS_RGB:
		{
			while (srcinfo.output_scanline < output_height) {
				if (g_cancellable_is_cancelled (cancellable))
					goto stop_loading;

				n_lines = jpeg_read_scanlines (&srcinfo, buffer, srcinfo.rec_outbuf_height);
				if (scanned_lines + n_lines > output_height)
					n_lines = output_height - scanned_lines;

				buffer_row = buffer;
				for (l = 0; l < n_lines; l++) {
					p_surface = surface_row;
					p_buffer = buffer_row[l];

					if (g_cancellable_is_cancelled (cancellable))
						goto stop_loading;

					for (x = 0; x < output_width; x++) {
						r = p_buffer[0];
						g = p_buffer[1];
						b = p_buffer[2];
						pixel = CAIRO_RGBA_TO_UINT32 (r, g, b, 0xff);
						memcpy (p_surface, &pixel, sizeof (guint32));

						p_surface += pixel_step;
						p_buffer += 3 /*srcinfo.output_components*/;
					}

					surface_row += line_step;
					buffer_row += buffer_stride;
					scanned_lines += 1;
				}
			}
		}
		break;

	case JCS_YCbCr:
		{
			register JSAMPLE *range_limit = srcinfo.sample_range_limit;
			register int     *r_cr_tab;
			register int     *g_cb_tab;
			register int     *g_cr_tab;
			register int     *b_cb_tab;
			int               Y, Cb, Cr;

			YCbCr_tables_init ();
			r_cr_tab = YCbCr_R_Cr_Tab;
			g_cb_tab = YCbCr_G_Cb_Tab;
			g_cr_tab = YCbCr_G_Cr_Tab;
			b_cb_tab = YCbCr_B_Cb_Tab;

			while (srcinfo.output_scanline < output_height) {
				if (g_cancellable_is_cancelled (cancellable))
					goto stop_loading;

				n_lines = jpeg_read_scanlines (&srcinfo, buffer, srcinfo.rec_outbuf_height);
				if (scanned_lines + n_lines > output_height)
					n_lines = output_height - scanned_lines;

				buffer_row = buffer;
				for (l = 0; l < n_lines; l++) {
					p_surface = surface_row;
					p_buffer = buffer_row[l];

					if (g_cancellable_is_cancelled (cancellable))
						goto stop_loading;

					for (x = 0; x < output_width; x++) {
						Y = p_buffer[0];
						Cb = p_buffer[1];
						Cr = p_buffer[2];

						r = range_limit[Y + r_cr_tab[Cr]];
						g = range_limit[Y + SCALE_DOWN (g_cb_tab[Cb] + g_cr_tab[Cr])];
						b = range_limit[Y + b_cb_tab[Cb]];
						pixel = CAIRO_RGBA_TO_UINT32 (r, g, b, 0xff);
						memcpy (p_surface, &pixel, sizeof (guint32));

						p_surface += pixel_step;
						p_buffer += 3 /*srcinfo.output_components*/;
					}

					surface_row += line_step;
					buffer_row += buffer_stride;
					scanned_lines += 1;
				}
			}
		}
		break;

	case JCS_YCCK:
		{
			register JSAMPLE *range_limit = srcinfo.sample_range_limit;
			register int     *r_cr_tab;
			register int     *g_cb_tab;
			register int     *g_cr_tab;
			register int     *b_cb_tab;
			register guchar  *cmyk_tab;
			int               Y, Cb, Cr, K, Ki, c, m , y;

			YCbCr_tables_init ();
			r_cr_tab = YCbCr_R_Cr_Tab;
			g_cb_tab = YCbCr_G_Cb_Tab;
			g_cr_tab = YCbCr_G_Cr_Tab;
			b_cb_tab = YCbCr_B_Cb_Tab;

			CMYK_table_init ();
			cmyk_tab = CMYK_Tab;

			while (srcinfo.output_scanline < output_height) {
				if (g_cancellable_is_cancelled (cancellable))
					goto stop_loading;

				n_lines = jpeg_read_scanlines (&srcinfo, buffer, srcinfo.rec_outbuf_height);
				if (scanned_lines + n_lines > output_height)
					n_lines = output_height - scanned_lines;

				buffer_row = buffer;
				for (l = 0; l < n_lines; l++) {
					p_surface = surface_row;
					p_buffer = buffer_row[l];

					if (g_cancellable_is_cancelled (cancellable))
						goto stop_loading;

					for (x = 0; x < output_width; x++) {
						Y = p_buffer[0];
						Cb = p_buffer[1];
						Cr = p_buffer[2];
						K = p_buffer[3];

						c = range_limit[255 - (Y + r_cr_tab[Cr])];
						m = range_limit[255 - (Y + SCALE_DOWN (g_cb_tab[Cb] + g_cr_tab[Cr]))];
						y = range_limit[255 - (Y + b_cb_tab[Cb])];

						Ki = K << 8; /* ki = K * 256 */

						r = cmyk_tab[Ki + c];
						g = cmyk_tab[Ki + m];
						b = cmyk_tab[Ki + y];
						pixel = CAIRO_RGBA_TO_UINT32 (r, g, b, 0xff);
						memcpy (p_surface, &pixel, sizeof (guint32));

						p_surface += pixel_step;
						p_buffer += 4 /*srcinfo.output_components*/;
					}

					surface_row += line_step;
					buffer_row += buffer_stride;
					scanned_lines += 1;
				}
			}
		}
		break;

	case JCS_UNKNOWN:
	default:
		g_set_error (error,
                             GDK_PIXBUF_ERROR,
                             GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
                             _("Unknown JPEG color space (%d)"),
                             srcinfo.out_color_space);
		break;
	}

	read_all_scanlines = TRUE;

	stop_loading:

	if (! finished) {
		finished = TRUE;

		if (surface != NULL) {
			cairo_surface_mark_dirty (surface);

			if (! g_cancellable_is_cancelled (cancellable)) {
				int original_width;
				int original_height;

				/* Set the original dimensions */

				if ((orientation == GTH_TRANSFORM_ROTATE_90)
					 ||	(orientation == GTH_TRANSFORM_ROTATE_270)
					 ||	(orientation == GTH_TRANSFORM_TRANSPOSE)
					 ||	(orientation == GTH_TRANSFORM_TRANSVERSE))
				{
					original_width = srcinfo.image_height;
					original_height = srcinfo.image_width;
				}
				else {
					original_width = srcinfo.image_width;
					original_height = srcinfo.image_height;
				}

				_cairo_metadata_set_original_size (metadata, original_width, original_height);

				if (original_width_p != NULL)
					*original_width_p = original_width;
				if (original_height_p != NULL)
					*original_height_p = original_height;
				if (loaded_original_p != NULL)
					*loaded_original_p = ! load_scaled;

				/*_cairo_image_surface_set_attribute_int (surface, "Image::Rotation", rotation); FIXME*/
				/* FIXME _cairo_image_surface_set_attribute (surface, "Jpeg::ColorSpace", jpeg_color_space_name (srcinfo.jpeg_color_space)); */

				gth_image_set_cairo_surface (image, surface);
			}
			else
				g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED, "");

			cairo_surface_destroy (surface);
			surface = NULL; /* ignore other jpeg errors */

		}

		if (read_all_scanlines)
			jpeg_finish_decompress (&srcinfo);
		else
			jpeg_abort_decompress (&srcinfo);
		jpeg_destroy_decompress (&srcinfo);
	}

	g_free (in_buffer);

	return image;
}


    double getCFVersion(int ncid)
    {
        double ver = -1.0;
        std::string attrVal;

        // Fetch the CF attribute
        if(attrf(ncid, NC_GLOBAL, NCDF_CONVENTIONS, attrVal) == "")
        {
            return ver;
        }

        if(sscanf(attrVal.c_str(), "CF-%lf", &ver) != 1)
        {
            return -1.0;
        }

        return ver;
    }


    void SGeometry_PropertyScanner::open(int container_id)
    {
        // First check for container_id, if variable doesn't exist error out
        if(nc_inq_var(this->nc, container_id, nullptr, nullptr, nullptr, nullptr, nullptr) != NC_NOERR)
        {
            return;    // change to exception
        }

        // Now exists, see what variables refer to this one
        // First get name of this container
        char contname[NC_MAX_NAME + 1];
        memset(contname, 0, NC_MAX_NAME + 1);
        if(nc_inq_varname(this->nc, container_id, contname) != NC_NOERR)
        {
            return;
        }

        // Then scan throughout the netcdfDataset if those variables geometry_container
        // atrribute matches the container
        int varCount = 0;
        if(nc_inq_nvars(this->nc, &varCount) != NC_NOERR)
        {
            return;
        }

        for(int curr = 0; curr < varCount; curr++)
        {
            size_t contname2_len = 0;

            // First find container length, and make buf that size in chars
            if(nc_inq_attlen(this->nc, curr, CF_SG_GEOMETRY, &contname2_len) != NC_NOERR)
            {
                // not a geometry variable, continue
                continue;
            }

            // Also if present but empty, go on
            if(contname2_len == 0) continue;

            // Otherwise, geometry: see what container it has
            char buf[NC_MAX_CHAR + 1];
            memset(buf, 0, NC_MAX_CHAR + 1);

            if(nc_get_att_text(this->nc, curr, CF_SG_GEOMETRY, buf)!= NC_NOERR)
            {
                continue;
            }

            // If matches, then establish a reference by placing this variable's data in both vectors
            if(!strcmp(contname, buf))
            {
                char property_name[NC_MAX_NAME];
                nc_inq_varname(this->nc, curr, property_name);

                std::string n(property_name);
                v_ids.push_back(curr);
                v_headers.push_back(n);
            }
        }
    }


    SG_Exception_Dep::SG_Exception_Dep(const char* container_name, const char* arg1, const char* arg2)
    {
        std::string cn_s(container_name);
        std::string arg1_s(arg1);
        std::string arg2_s(arg2);

        this -> err_msg = "[" + cn_s + "] The attribute "
                + arg1_s
                + " may not exist without the attribute "
                + arg2_s
                + " existing.";
    }


OGRKMLLayer::~OGRKMLLayer()
{
    if( nullptr != poFeatureDefn_ )
        poFeatureDefn_->Release();

    if( nullptr != poSRS_ )
        poSRS_->Release();

    if( nullptr != poCT_ )
        delete poCT_;

    CPLFree( pszName_ );
}


OGRErr OGRKMLLayer::CreateField( OGRFieldDefn *poField,
                                 CPL_UNUSED int bApproxOK )
{
    if( !bWriter_ || iNextKMLId_ != 0 )
        return OGRERR_FAILURE;

    OGRFieldDefn oCleanCopy( poField );
    poFeatureDefn_->AddFieldDefn( &oCleanCopy );

    return OGRERR_NONE;
}


check_CT_CLEAR(const struct ofpact_null *a OVS_UNUSED,
               const struct ofpact_check_params *cp OVS_UNUSED)
{
    return 0;
}


format_CONTROLLER(const struct ofpact_controller *a,
                  const struct ofpact_format_params *fp)
{
    if (a->reason == OFPR_ACTION && !a->controller_id && !a->userdata_len
        && !a->pause && a->meter_id == NX_CTLR_NO_METER) {
        ds_put_format(fp->s, "%sCONTROLLER:%s%"PRIu16,
                      colors.special, colors.end, a->max_len);
    } else {
        enum ofp_packet_in_reason reason = a->reason;

        ds_put_format(fp->s, "%scontroller(%s", colors.paren, colors.end);
        if (reason != OFPR_ACTION) {
            char reasonbuf[OFPUTIL_PACKET_IN_REASON_BUFSIZE];

            ds_put_format(fp->s, "%sreason=%s%s,", colors.param, colors.end,
                          ofputil_packet_in_reason_to_string(
                              reason, reasonbuf, sizeof reasonbuf));
        }
        if (a->max_len != UINT16_MAX) {
            ds_put_format(fp->s, "%smax_len=%s%"PRIu16",",
                          colors.param, colors.end, a->max_len);
        }
        if (a->controller_id != 0) {
            ds_put_format(fp->s, "%sid=%s%"PRIu16",",
                          colors.param, colors.end, a->controller_id);
        }
        if (a->userdata_len) {
            ds_put_format(fp->s, "%suserdata=%s", colors.param, colors.end);
            format_hex_arg(fp->s, a->userdata, a->userdata_len);
            ds_put_char(fp->s, ',');
        }
        if (a->pause) {
            ds_put_format(fp->s, "%spause%s,", colors.value, colors.end);
        }
        if (a->meter_id != NX_CTLR_NO_METER) {
            ds_put_format(fp->s, "%smeter_id=%s%"PRIu32",",
                          colors.param, colors.end, a->meter_id);
        }
        ds_chomp(fp->s, ',');
        ds_put_format(fp->s, "%s)%s", colors.paren, colors.end);
    }
}


ofpacts_pull_openflow_instructions(struct ofpbuf *openflow,
                                   unsigned int instructions_len,
                                   enum ofp_version version,
                                   const struct vl_mff_map *vl_mff_map,
                                   uint64_t *ofpacts_tlv_bitmap,
                                   struct ofpbuf *ofpacts)
{
    const struct ofp11_instruction *instructions;
    const struct ofp11_instruction *insts[N_OVS_INSTRUCTIONS];
    enum ofperr error;

    ofpbuf_clear(ofpacts);
    if (version == OFP10_VERSION) {
        return ofpacts_pull_openflow_actions__(openflow, instructions_len,
                                               version,
                                               (1u << N_OVS_INSTRUCTIONS) - 1,
                                               ofpacts, 0, vl_mff_map,
                                               ofpacts_tlv_bitmap);
    }

    if (instructions_len % OFP11_INSTRUCTION_ALIGN != 0) {
        VLOG_WARN_RL(&rl, "OpenFlow message instructions length %u is not a "
                     "multiple of %d",
                     instructions_len, OFP11_INSTRUCTION_ALIGN);
        error = OFPERR_OFPBIC_BAD_LEN;
        goto exit;
    }

    instructions = ofpbuf_try_pull(openflow, instructions_len);
    if (instructions == NULL) {
        VLOG_WARN_RL(&rl, "OpenFlow message instructions length %u exceeds "
                     "remaining message length (%"PRIu32")",
                     instructions_len, openflow->size);
        error = OFPERR_OFPBIC_BAD_LEN;
        goto exit;
    }

    error = decode_openflow11_instructions(
        instructions, instructions_len / OFP11_INSTRUCTION_ALIGN, version,
        insts);
    if (error) {
        goto exit;
    }

    if (insts[OVSINST_OFPIT13_METER]) {
        const struct ofp13_instruction_meter *oim;
        struct ofpact_meter *om;

        oim = ALIGNED_CAST(const struct ofp13_instruction_meter *,
                           insts[OVSINST_OFPIT13_METER]);

        om = ofpact_put_METER(ofpacts);
        om->meter_id = ntohl(oim->meter_id);
        om->provider_meter_id = UINT32_MAX; /* No provider meter ID. */
    }
    if (insts[OVSINST_OFPIT11_APPLY_ACTIONS]) {
        const struct ofp_action_header *actions;
        size_t actions_len;

        get_actions_from_instruction(insts[OVSINST_OFPIT11_APPLY_ACTIONS],
                                     &actions, &actions_len);
        error = ofpacts_decode(actions, actions_len, version, vl_mff_map,
                               ofpacts_tlv_bitmap, ofpacts);
        if (error) {
            goto exit;
        }
    }
    if (insts[OVSINST_OFPIT11_CLEAR_ACTIONS]) {
        instruction_get_OFPIT11_CLEAR_ACTIONS(
            insts[OVSINST_OFPIT11_CLEAR_ACTIONS]);
        ofpact_put_CLEAR_ACTIONS(ofpacts);
    }
    if (insts[OVSINST_OFPIT11_WRITE_ACTIONS]) {
        struct ofpact_nest *on;
        const struct ofp_action_header *actions;
        size_t actions_len;
        size_t start = ofpacts->size;
        ofpact_put(ofpacts, OFPACT_WRITE_ACTIONS,
                   offsetof(struct ofpact_nest, actions));
        get_actions_from_instruction(insts[OVSINST_OFPIT11_WRITE_ACTIONS],
                                     &actions, &actions_len);
        error = ofpacts_decode_for_action_set(actions, actions_len,
                                              version, vl_mff_map,
                                              ofpacts_tlv_bitmap, ofpacts);
        if (error) {
            goto exit;
        }
        on = ofpbuf_at_assert(ofpacts, start, sizeof *on);
        on->ofpact.len = ofpacts->size - start;
    }
    if (insts[OVSINST_OFPIT11_WRITE_METADATA]) {
        const struct ofp11_instruction_write_metadata *oiwm;
        struct ofpact_metadata *om;

        oiwm = ALIGNED_CAST(const struct ofp11_instruction_write_metadata *,
                            insts[OVSINST_OFPIT11_WRITE_METADATA]);

        om = ofpact_put_WRITE_METADATA(ofpacts);
        om->metadata = oiwm->metadata;
        om->mask = oiwm->metadata_mask;
    }
    if (insts[OVSINST_OFPIT11_GOTO_TABLE]) {
        const struct ofp11_instruction_goto_table *oigt;
        struct ofpact_goto_table *ogt;

        oigt = instruction_get_OFPIT11_GOTO_TABLE(
            insts[OVSINST_OFPIT11_GOTO_TABLE]);
        ogt = ofpact_put_GOTO_TABLE(ofpacts);
        ogt->table_id = oigt->table_id;
    }

    error = ofpacts_verify(ofpacts->data, ofpacts->size, version,
                           (1u << N_OVS_INSTRUCTIONS) - 1, 0, NULL);
exit:
    if (error) {
        ofpbuf_clear(ofpacts);
    }
    return error;
}


check_DECAP(const struct ofpact_decap *a OVS_UNUSED,
            struct ofpact_check_params *cp)
{
    struct flow *flow = &cp->match->flow;
    if (flow->packet_type == htonl(PT_ETH)) {
        /* Adjust the packet_type to allow subsequent actions. */
        flow->packet_type = PACKET_TYPE_BE(OFPHTN_ETHERTYPE,
                                           ntohs(flow->dl_type));
    } else {
        /* The actual packet_type is only known after decapsulation.
         * Do not allow subsequent actions that depend on packet headers. */
        flow->packet_type = htonl(PT_UNKNOWN);
        flow->dl_type = OVS_BE16_MAX;
    }
    return 0;
}


check_SET_IP_ECN(const struct ofpact_ecn *a OVS_UNUSED,
                 struct ofpact_check_params *cp)
{
    return check_set_ip(cp);
}


ofpacts_parse_actions(const char *s, const struct ofpact_parse_params *pp)
{
    return ofpacts_parse_copy(s, pp, false, 0);
}


check_OUTPUT_TRUNC(const struct ofpact_output_trunc *a,
                   const struct ofpact_check_params *cp)
{
    return ofpact_check_output_port(a->port, cp->max_ports);
}


format_GROUP(const struct ofpact_group *a,
             const struct ofpact_format_params *fp)
{
    ds_put_format(fp->s, "%sgroup:%s%"PRIu32,
                  colors.special, colors.end, a->group_id);
}


decode_NXAST_RAW_CLONE(const struct ext_action_header *eah,
                       enum ofp_version ofp_version,
                       const struct vl_mff_map *vl_mff_map,
                       uint64_t *tlv_bitmap, struct ofpbuf *out)
{
    int error;
    struct ofpbuf openflow;
    const size_t clone_offset = ofpacts_pull(out);
    struct ofpact_nest *clone = ofpact_put_CLONE(out);

    /* decode action list */
    ofpbuf_pull(out, sizeof(*clone));
    openflow = ofpbuf_const_initializer(
                    eah + 1, ntohs(eah->len) - sizeof *eah);
    error = ofpacts_pull_openflow_actions__(&openflow, openflow.size,
                                            ofp_version,
                                            1u << OVSINST_OFPIT11_APPLY_ACTIONS,
                                            out, 0, vl_mff_map, tlv_bitmap);
    if (error) {
        return error;
    }
    clone = ofpbuf_push_uninit(out, sizeof *clone);
    out->header = &clone->ofpact;
    ofpact_finish_CLONE(out, &clone);
    ofpbuf_push_uninit(out, clone_offset);
    return error;
}


ofpacts_check_consistency(struct ofpact ofpacts[], size_t ofpacts_len,
                          enum ofputil_protocol needed_protocols,
                          struct ofpact_check_params *cp)
{
    enum ofperr error = ofpacts_check(ofpacts, ofpacts_len, cp);
    if (!error && needed_protocols & ~cp->usable_protocols) {
        return OFPERR_OFPBAC_MATCH_INCONSISTENT;
    }
    return error;
}


parse_noargs_dec_ttl(const struct ofpact_parse_params *pp)
{
    struct ofpact_cnt_ids *ids;
    uint16_t id = 0;

    ofpact_put_DEC_TTL(pp->ofpacts);
    ofpbuf_put(pp->ofpacts, &id, sizeof id);
    ids = pp->ofpacts->header;
    ids->n_controllers++;
    ofpact_finish_DEC_TTL(pp->ofpacts, &ids);
}


check_SET_MPLS_LABEL(const struct ofpact_mpls_label *a OVS_UNUSED,
                     struct ofpact_check_params *cp)
{
    return check_set_mpls(cp);
}


ofpacts_verify(const struct ofpact ofpacts[], size_t ofpacts_len,
               enum ofp_version version, uint32_t allowed_ovsinsts,
               enum ofpact_type outer_action, char **errorp)
{
    const struct ofpact *a;
    enum ovs_instruction_type inst;

    inst = OVSINST_OFPIT13_METER;
    OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
        enum ovs_instruction_type next;
        enum ofperr error;

        if (a->type == OFPACT_CONJUNCTION) {
            OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
                if (a->type != OFPACT_CONJUNCTION && a->type != OFPACT_NOTE) {
                    verify_error(errorp, "\"conjunction\" actions may be used "
                                 "along with \"note\" but not any other kind "
                                 "of action (such as the \"%s\" action used "
                                 "here)", ofpact_name(a->type));
                    return OFPERR_NXBAC_BAD_CONJUNCTION;
                }
            }
            return 0;
        }

        error = ofpacts_verify_nested(a, outer_action, errorp);
        if (error) {
            return error;
        }

        next = ovs_instruction_type_from_ofpact_type(a->type, version);
        if (a > ofpacts
            && (inst == OVSINST_OFPIT11_APPLY_ACTIONS
                ? next < inst
                : next <= inst)) {
            const char *name = ovs_instruction_name_from_type(inst);
            const char *next_name = ovs_instruction_name_from_type(next);

            if (next == inst) {
                verify_error(errorp, "duplicate %s instruction not allowed, "
                             "for OpenFlow 1.1+ compatibility", name);
            } else {
                verify_error(errorp, "invalid instruction ordering: "
                             "%s must appear before %s, "
                             "for OpenFlow 1.1+ compatibility",
                             next_name, name);
            }
            return OFPERR_OFPBAC_UNSUPPORTED_ORDER;
        }
        if (!((1u << next) & allowed_ovsinsts)) {
            const char *name = ovs_instruction_name_from_type(next);

            if (next == OVSINST_OFPIT13_METER && version >= OFP15_VERSION) {
                verify_error(errorp, "%s action not allowed here", name);
                return OFPERR_OFPBAC_BAD_TYPE;
            } else {
                verify_error(errorp, "%s instruction not allowed here", name);
                return OFPERR_OFPBIC_UNSUP_INST;
            }
        }

        inst = next;
    }

    return 0;
}


format_STRIP_VLAN(const struct ofpact_null *a,
                  const struct ofpact_format_params *fp)
{
    ds_put_format(fp->s, (a->ofpact.raw == OFPAT_RAW11_POP_VLAN
                    ? "%spop_vlan%s"
                    : "%sstrip_vlan%s"),
                  colors.value, colors.end);
}


check_DEBUG_RECIRC(const struct ofpact_null *a OVS_UNUSED,
                   const struct ofpact_check_params *cp OVS_UNUSED)
{
    return 0;
}


format_SET_QUEUE(const struct ofpact_queue *a,
                 const struct ofpact_format_params *fp)
{
    ds_put_format(fp->s, "%sset_queue:%s%"PRIu32,
                  colors.param, colors.end, a->queue_id);
}


format_SET_IP_TTL(const struct ofpact_ip_ttl *a,
                  const struct ofpact_format_params *fp)
{
    ds_put_format(fp->s, "%smod_nw_ttl:%s%d",
                  colors.param, colors.end, a->ttl);
}


parse_SET_IPV4_SRC(char *arg, const struct ofpact_parse_params *pp)
{
    return str_to_ip(arg, &ofpact_put_SET_IPV4_SRC(pp->ofpacts)->ipv4);
}


encode_METER(const struct ofpact_meter *meter,
             enum ofp_version ofp_version, struct ofpbuf *out)
{
    if (ofp_version == OFP13_VERSION || ofp_version == OFP14_VERSION) {
        instruction_put_OFPIT13_METER(out)->meter_id = htonl(meter->meter_id);
    } else if (ofp_version >= OFP15_VERSION) {
        put_OFPAT15_METER(out, meter->meter_id);
    }
}


format_SET_IPV4_SRC(const struct ofpact_ipv4 *a,
                    const struct ofpact_format_params *fp)
{
    ds_put_format(fp->s, "%smod_nw_src:%s"IP_FMT,
                  colors.param, colors.end, IP_ARGS(a->ipv4));
}


parse_ENCAP(char *arg, const struct ofpact_parse_params *pp)
{
    struct ofpact_encap *encap;
    char *key, *value, *str;
    char *error = NULL;
    uint16_t prop_class;
    int n_props = 0;

    encap = ofpact_put_ENCAP(pp->ofpacts);
    encap->hdr_size = 0;
    /* Parse encap header type. */
    str = arg;
    if (!ofputil_parse_key_value(&arg, &key, &value)) {
        return xasprintf("Missing encap hdr: %s", str);
    }
    if (!parse_encap_header(key, &encap->new_pkt_type)) {
        return xasprintf("Encap hdr not supported: %s", value);
    }
    if (!parse_ed_prop_class(key, &prop_class)) {
        return xasprintf("Invalid encap prop class: %s", key);
    }
    /* Parse encap properties. */
    error = parse_ed_props(prop_class, &value, &n_props, pp->ofpacts);
    if (error != NULL) {
        return error;
    }
    /* ofpbuf may have been re-allocated. */
    encap = pp->ofpacts->header;
    encap->n_props = n_props;
    ofpact_finish_ENCAP(pp->ofpacts, &encap);
    return NULL;
}


Pl_ASCII85Decoder::flush()
{
    if (this->pos == 0)
    {
	QTC::TC("libtests", "Pl_ASCII85Decoder no-op flush");
	return;
    }
    unsigned long lval = 0;
    for (int i = 0; i < 5; ++i)
    {
	lval *= 85;
	lval += (this->inbuf[i] - 33U);
    }

    unsigned char outbuf[4];
    memset(outbuf, 0, 4);
    for (int i = 3; i >= 0; --i)
    {
	outbuf[i] = lval & 0xff;
	lval >>= 8;
    }

    QTC::TC("libtests", "Pl_ASCII85Decoder partial flush",
	    (this->pos == 5) ? 0 : 1);
    // Reset before calling getNext()->write in case that throws an
    // exception.
    auto t = this->pos - 1;
    this->pos = 0;
    memset(this->inbuf, 117, 5);

    getNext()->write(outbuf, t);
}


Pl_AES_PDF::useStaticIV()
{
    use_static_iv = true;
}


Pl_Count::getCount() const
{
    return this->m->count;
}