/* ###
 * IP: GHIDRA
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
// Adds a SourceFile with a user-defined path and name to the program.
//@category Source Mapping
import java.util.HexFormat;

import org.apache.commons.lang3.StringUtils;

import ghidra.app.script.GhidraScript;
import ghidra.features.base.values.GhidraValuesMap;
import ghidra.program.database.sourcemap.SourceFile;
import ghidra.program.database.sourcemap.SourceFileIdType;
import ghidra.util.MessageType;

public class AddSourceFileScript extends GhidraScript {

	private static final String PATH = "Source File Path";
	private static final String ID_TYPE = "Id Type";
	private static final String IDENTIFIER = "Identifier";

	@Override
	protected void run() throws Exception {
		if (isRunningHeadless()) {
			println("This script must be run through the Ghidra GUI");
			return;
		}
		if (currentProgram == null) {
			popup("This script requires an open program");
			return;
		}
		if (!currentProgram.hasExclusiveAccess()) {
			popup("This script requires exclusive access to the program");
			return;
		}

		GhidraValuesMap values = new GhidraValuesMap();
		values.defineString(PATH, "/");
		SourceFileIdType[] idTypes = SourceFileIdType.values();
		String[] enumNames = new String[idTypes.length];
		for (int i = 0; i < enumNames.length; ++i) {
			enumNames[i] = idTypes[i].name();
		}
		values.defineChoice(ID_TYPE, SourceFileIdType.NONE.name(), enumNames);
		values.defineString(IDENTIFIER, StringUtils.EMPTY);

		values.setValidator((valueMap, status) -> {
			String path = valueMap.getString(PATH);
			SourceFileIdType idType = SourceFileIdType.valueOf(values.getChoice(ID_TYPE));
			byte[] identifier = null;
			if (idType != SourceFileIdType.NONE) {
				identifier = HexFormat.of().parseHex(values.getString(IDENTIFIER));
			}
			try {
				SourceFile srcFile = new SourceFile(path, idType, identifier);
				if (currentProgram.getSourceFileManager().containsSourceFile(srcFile)) {
					status.setStatusText("SourceFile " + srcFile + " already exists",
						MessageType.ERROR);
					return false;
				}
			}
			catch (IllegalArgumentException e) {
				status.setStatusText(e.getMessage(), MessageType.ERROR);
				return false;
			}
			return true;
		});
		askValues("Enter (Absolute) Source File URI Path",
			"e.g.: /usr/bin/echo, /C:/Programs/file.exe", values);
		String absolutePath = values.getString(PATH);
		SourceFileIdType idType = SourceFileIdType.valueOf(values.getChoice(ID_TYPE));
		byte[] identifier = null;
		if (idType != SourceFileIdType.NONE) {
			identifier = HexFormat.of().parseHex(values.getString(IDENTIFIER));
		}
		SourceFile srcFile = new SourceFile(absolutePath, idType, identifier);
		currentProgram.getSourceFileManager().addSourceFile(srcFile);
		printf("Successfully added source file %s%n", srcFile.toString());
	}

}
