static bool data_transfer_layersmapping_cdlayers(
        ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights,
        const int num_elem_dst, const bool use_create, const bool use_delete,
        CustomData *cd_src, CustomData *cd_dst, const bool use_dupref_dst,
        const int fromlayers, const int tolayers)
{
	int idx_src, idx_dst;
	void *data_src, *data_dst = NULL;

	if (CustomData_layertype_is_singleton(cddata_type)) {
		if (!(data_src = CustomData_get_layer(cd_src, cddata_type))) {
			if (use_delete) {
				CustomData_free_layer(cd_dst, cddata_type, num_elem_dst, 0);
			}
			return true;
		}

		data_dst = CustomData_get_layer(cd_dst, cddata_type);
		if (!data_dst) {
			if (!use_create) {
				return true;
			}
			data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst);
		}
		else if (use_dupref_dst && r_map) {
			/* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
			data_dst = CustomData_duplicate_referenced_layer(cd_dst, cddata_type, num_elem_dst);
		}

		if (r_map) {
			data_transfer_layersmapping_add_item_cd(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
			                                        data_src, data_dst);
		}
	}
	else if (fromlayers == DT_LAYERS_ACTIVE_SRC || fromlayers >= 0) {
		/* Note: use_delete has not much meaning in this case, ignored. */

		if (fromlayers >= 0) {  /* Real-layer index */
			idx_src = fromlayers;
		}
		else {
			if ((idx_src = CustomData_get_active_layer(cd_src, cddata_type)) == -1) {
				return true;
			}
		}
		data_src = CustomData_get_layer_n(cd_src, cddata_type, idx_src);
		if (!data_src) {
			return true;
		}

		if (tolayers >= 0) {  /* Real-layer index */
			idx_dst = tolayers;
			/* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
			if (use_dupref_dst && r_map) {
				data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
			}
			else {
				data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst);
			}
		}
		else if (tolayers == DT_LAYERS_ACTIVE_DST) {
			if ((idx_dst = CustomData_get_active_layer(cd_dst, cddata_type)) == -1) {
				if (!use_create) {
					return true;
				}
				data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst);
			}
			else {
				/* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
				if (use_dupref_dst && r_map) {
					data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
				}
				else {
					data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst);
				}
			}
		}
		else if (tolayers == DT_LAYERS_INDEX_DST) {
			int num = CustomData_number_of_layers(cd_dst, cddata_type);
			idx_dst = idx_src;
			if (num <= idx_dst) {
				if (!use_create) {
					return true;
				}
				/* Create as much data layers as necessary! */
				for (; num <= idx_dst; num++) {
					CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst);
				}
			}
			/* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
			if (use_dupref_dst && r_map) {
				data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
			}
			else {
				data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst);
			}
		}
		else if (tolayers == DT_LAYERS_NAME_DST) {
			const char *name = CustomData_get_layer_name(cd_src, cddata_type, idx_src);
			if ((idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name)) == -1) {
				if (!use_create) {
					return true;
				}
				CustomData_add_layer_named(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst, name);
				idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name);
			}
			/* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
			if (use_dupref_dst && r_map) {
				data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
			}
			else {
				data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst);
			}
		}
		else {
			return false;
		}

		if (!data_dst) {
			return false;
		}

		if (r_map) {
			data_transfer_layersmapping_add_item_cd(
			        r_map, cddata_type, mix_mode, mix_factor, mix_weights, data_src, data_dst);
		}
	}
	else if (fromlayers == DT_LAYERS_ALL_SRC) {
		int num_src = CustomData_number_of_layers(cd_src, cddata_type);
		bool *use_layers_src = num_src ? MEM_mallocN(sizeof(*use_layers_src) * (size_t)num_src, __func__) : NULL;
		bool ret;

		if (use_layers_src) {
			memset(use_layers_src, true, sizeof(*use_layers_src) * num_src);
		}

		ret = data_transfer_layersmapping_cdlayers_multisrc_to_dst(
		        r_map, cddata_type, mix_mode, mix_factor, mix_weights,
		        num_elem_dst, use_create, use_delete, cd_src, cd_dst, use_dupref_dst,
		        tolayers, use_layers_src, num_src);

		if (use_layers_src) {
			MEM_freeN(use_layers_src);
		}
		return ret;
	}
	else {
		return false;
	}

	return true;
}
/* Note: rna_enum_dt_layers_select_src_items enum is from rna_modifier.c */
static EnumPropertyItem *dt_layers_select_src_itemf(
        bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
{
	EnumPropertyItem *item = NULL, tmp_item = {0};
	int totitem = 0;

	const int data_type = RNA_enum_get(ptr, "data_type");

	if (!C) {  /* needed for docs and i18n tools */
		return rna_enum_dt_layers_select_src_items;
	}

	RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_ACTIVE_SRC);
	RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_ALL_SRC);

	if (data_type == DT_TYPE_MDEFORMVERT) {
		Object *ob_src = CTX_data_active_object(C);

		if (BKE_object_pose_armature_get(ob_src)) {
			RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_SELECT);
			RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_DEFORM);
		}

		if (ob_src) {
			bDeformGroup *dg;
			int i;

			RNA_enum_item_add_separator(&item, &totitem);

			for (i = 0, dg = ob_src->defbase.first; dg; i++, dg = dg->next) {
				tmp_item.value = i;
				tmp_item.identifier = tmp_item.name = dg->name;
				RNA_enum_item_add(&item, &totitem, &tmp_item);
			}
		}
	}
	else if (data_type == DT_TYPE_SHAPEKEY) {
		/* TODO */
	}
	else if (data_type == DT_TYPE_UV) {
		Object *ob_src = CTX_data_active_object(C);
		Scene *scene = CTX_data_scene(C);

		if (ob_src) {
			DerivedMesh *dm_src;
			CustomData *pdata;
			int num_data, i;

			/* XXX Is this OK? */
			dm_src = mesh_get_derived_final(scene, ob_src, CD_MASK_BAREMESH | CD_MTEXPOLY);
			pdata = dm_src->getPolyDataLayout(dm_src);
			num_data = CustomData_number_of_layers(pdata, CD_MTEXPOLY);

			RNA_enum_item_add_separator(&item, &totitem);

			for (i = 0; i < num_data; i++) {
				tmp_item.value = i;
				tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(pdata, CD_MTEXPOLY, i);
				RNA_enum_item_add(&item, &totitem, &tmp_item);
			}
		}
	}
	else if (data_type == DT_TYPE_VCOL) {
		Object *ob_src = CTX_data_active_object(C);
		Scene *scene = CTX_data_scene(C);

		if (ob_src) {
			DerivedMesh *dm_src;
			CustomData *ldata;
			int num_data, i;

			/* XXX Is this OK? */
			dm_src = mesh_get_derived_final(scene, ob_src, CD_MASK_BAREMESH | CD_MLOOPCOL);
			ldata = dm_src->getLoopDataLayout(dm_src);
			num_data = CustomData_number_of_layers(ldata, CD_MLOOPCOL);

			RNA_enum_item_add_separator(&item, &totitem);

			for (i = 0; i < num_data; i++) {
				tmp_item.value = i;
				tmp_item.identifier = tmp_item.name = CustomData_get_layer_name(ldata, CD_MLOOPCOL, i);
				RNA_enum_item_add(&item, &totitem, &tmp_item);
			}
		}
	}

	RNA_enum_item_end(&item, &totitem);
	*r_free = true;

	return item;
}
static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(
        ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights,
        const int num_elem_dst, const bool use_create, const bool use_delete,
        CustomData *cd_src, CustomData *cd_dst, const bool use_dupref_dst,
        const int tolayers, bool *use_layers_src, const int num_layers_src)
{
	void *data_src, *data_dst = NULL;
	int idx_src = num_layers_src;
	int idx_dst, tot_dst = CustomData_number_of_layers(cd_dst, cddata_type);
	bool *data_dst_to_delete = NULL;

	if (!use_layers_src) {
		/* No source at all, we can only delete all dest if requested... */
		if (use_delete) {
			idx_dst = tot_dst;
			while (idx_dst--) {
				CustomData_free_layer(cd_dst, cddata_type, num_elem_dst, idx_dst);
			}
		}
		return true;
	}

	switch (tolayers) {
		case DT_LAYERS_INDEX_DST:
			idx_dst = tot_dst;

			/* Find last source actually used! */
			while (idx_src-- && !use_layers_src[idx_src]);
			idx_src++;

			if (idx_dst < idx_src) {
				if (!use_create) {
					return true;
				}
				/* Create as much data layers as necessary! */
				for (; idx_dst < idx_src; idx_dst++) {
					CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst);
				}
			}
			else if (use_delete && idx_dst > idx_src) {
				while (idx_dst-- > idx_src) {
					CustomData_free_layer(cd_dst, cddata_type, num_elem_dst, idx_dst);
				}
			}
			if (r_map) {
				while (idx_src--) {
					if (!use_layers_src[idx_src]) {
						continue;
					}
					data_src = CustomData_get_layer_n(cd_src, cddata_type, idx_src);
					/* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
					if (use_dupref_dst) {
						data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_src, num_elem_dst);
					}
					else {
						data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_src);
					}
					data_transfer_layersmapping_add_item_cd(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
					                                        data_src, data_dst);
				}
			}
			break;
		case DT_LAYERS_NAME_DST:
			if (use_delete) {
				if (tot_dst) {
					data_dst_to_delete = MEM_mallocN(sizeof(*data_dst_to_delete) * (size_t)tot_dst, __func__);
					memset(data_dst_to_delete, true, sizeof(*data_dst_to_delete) * (size_t)tot_dst);
				}
			}

			while (idx_src--) {
				const char *name;

				if (!use_layers_src[idx_src]) {
					continue;
				}

				name = CustomData_get_layer_name(cd_src, cddata_type, idx_src);
				data_src = CustomData_get_layer_n(cd_src, cddata_type, idx_src);

				if ((idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name)) == -1) {
					if (!use_create) {
						if (r_map) {
							BLI_freelistN(r_map);
						}
						return true;
					}
					CustomData_add_layer_named(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst, name);
					idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name);
				}
				else if (data_dst_to_delete) {
					data_dst_to_delete[idx_dst] = false;
				}
				if (r_map) {
					/* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
					if (use_dupref_dst) {
						data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
					}
					else {
						data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst);
					}
					data_transfer_layersmapping_add_item_cd(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
					                                        data_src, data_dst);
				}
			}

			if (data_dst_to_delete) {
				/* Note: This won't affect newly created layers, if any, since tot_dst has not been updated!
				 *       Also, looping backward ensures us we do not suffer from index shifting when deleting a layer.
				 */
				for (idx_dst = tot_dst; idx_dst--;) {
					if (data_dst_to_delete[idx_dst]) {
						CustomData_free_layer(cd_dst, cddata_type, num_elem_dst, idx_dst);
					}
				}

				MEM_freeN(data_dst_to_delete);
			}
			break;
		default:
			return false;
	}

	return true;
}