/* ###
 * 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.
 */
package ghidra.app.util.bin.format.objc.objc2;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import ghidra.app.util.opinion.DyldCacheLoader;
import ghidra.app.util.opinion.MachoLoader;
import ghidra.program.model.data.CategoryPath;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.MemoryBlock;

public final class Objc2Constants {

	/**
	 * The name prefix of all Objective-C 2 sections.
	 */
	public final static String OBJC2_PREFIX = "__objc_";

	public final static String OBJC2_CATEGORY_LIST = "__objc_catlist";
	public final static String OBJC2_CLASS_LIST = "__objc_classlist";
	public final static String OBJC2_CLASS_REFS = "__objc_classrefs";
	public final static String OBJC2_CONST = "__objc_const";
	public final static String OBJC2_DATA = "__objc_data";
	public final static String OBJC2_IMAGE_INFO = "__objc_imageinfo";
	public final static String OBJC2_MESSAGE_REFS = "__objc_msgrefs";
	public final static String OBJC2_NON_LAZY_CLASS_LIST = "__objc_nlclslist";
	public final static String OBJC2_PROTOCOL_LIST = "__objc_protolist";
	public final static String OBJC2_PROTOCOL_REFS = "__objc_protorefs";
	public final static String OBJC2_SELECTOR_REFS = "__objc_selrefs";
	public final static String OBJC2_SUPER_REFS = "__objc_superrefs";

	/**
	 * Returns a list containing valid Objective-C 2.0 section names.
	 * @return a list containing valid Objective-C 2.0 section names
	 */
	public final static List<String> getObjectiveC2SectionNames() {
		List<String> sectionNames = new ArrayList<String>();
		Field[] declaredFields = Objc2Constants.class.getDeclaredFields();
		for (Field field : declaredFields) {
			try {
				if (field.get(null) instanceof String name && !name.equals(OBJC2_PREFIX) &&
					name.startsWith(OBJC2_PREFIX)) {
					sectionNames.add(name);
				}
			}
			catch (IllegalAccessException e) {
				// do nothing
			}
		}
		sectionNames.add("__data");//not really an Objective-C 2.0 section, but it contains structures used by Objective-C 2.0
		return sectionNames;
	}

	/**
	 * Returns true if this program contains Objective-C 2.
	 * @param program the program to check
	 * @return true if the program contains Objective-C 2.
	 */
	public final static boolean isObjectiveC2(Program program) {
		String format = program.getExecutableFormat();
		if (MachoLoader.MACH_O_NAME.equals(format) ||
			DyldCacheLoader.DYLD_CACHE_NAME.equals(format) ||
			"Extracted DYLD Component".equals(format)) {
			MemoryBlock[] blocks = program.getMemory().getBlocks();
			for (MemoryBlock memoryBlock : blocks) {
				if (memoryBlock.getName().startsWith(OBJC2_PREFIX)) {
					return true;
				}
			}
		}
		return false;
	}

	public final static String NAMESPACE = "objc2";

	public final static String CATEGORY = "/_objc2_";

	public final static CategoryPath CATEGORY_PATH = new CategoryPath(CATEGORY);
}
