private void addInfo(BasicJvmClassBundle classes,
	                     BasicFileBundle files,
	                     Map<String, AndroidClassBundle> androidClassBundles,
	                     NavigableMap<Integer, VersionedJvmClassBundle> versionedJvmClassBundles,
	                     Map<String, WorkspaceFileResource> embeddedResources,
	                     ByteSource infoSource,
	                     String pathName,
	                     Info info) {
		if (info.isClass()) {
			// Must be a JVM class since Android classes do not exist in single-file form.
			JvmClassInfo classInfo = info.asClass().asJvmClass();
			String className = classInfo.getName();

			// JVM edge case allows trailing '/' for class entries in JARs.
			// We're going to normalize that away.
			if (pathName.endsWith(".class/")) {
				pathName = pathName.replace(".class/", ".class");
			}

			// Record the class name, including path suffix/prefix.
			// If the name is totally different, record the original path name.
			int index = pathName.indexOf(className);
			if (index >= 0) {
				// Class name is within the entry name.
				// Record the prefix before the class name, and suffix after it (extension).
				if (index > 0) {
					String prefix = pathName.substring(0, index);
					PathPrefixProperty.set(classInfo, prefix);
				}
				int suffixIndex = index + className.length();
				if (suffixIndex < pathName.length()) {
					String suffix = pathName.substring(suffixIndex);
					PathSuffixProperty.set(classInfo, suffix);
				}
			} else {
				// Class name doesn't match entry name.
				PathOriginalNameProperty.set(classInfo, pathName);
			}

			// First we must handle edge cases. Up first, we'll look at multi-release jar prefixes.
			if (pathName.startsWith(JarFileInfo.MULTI_RELEASE_PREFIX) &&
					!className.startsWith(JarFileInfo.MULTI_RELEASE_PREFIX)) {
				String versionName = "<null>";
				try {
					// Extract version from '<prefix>/version/<class-name>' pattern
					int startOffset = JarFileInfo.MULTI_RELEASE_PREFIX.length();
					int slashIndex = pathName.indexOf('/', startOffset);
					if (slashIndex < 0)
						throw new NumberFormatException("Version name is null");
					versionName = pathName.substring(startOffset, slashIndex);

					// Only add if the names match
					int classStart = slashIndex + 1;
					int classEnd = pathName.length() - ".class".length();
					if (classEnd > classStart) {
						String classPath = pathName.substring(classStart, classEnd);
						if (!classPath.equals(className))
							throw new IllegalArgumentException("Class in multi-release directory" +
									" does not match it's declared class name: " + classPath);
					} else {
						throw new IllegalArgumentException("Class in multi-release directory " +
								"does not end in '.class'");
					}

					// Put it into the correct versioned class bundle.
					int version = Integer.parseInt(versionName);
					BasicJvmClassBundle bundle = (BasicJvmClassBundle) versionedJvmClassBundles
							.computeIfAbsent(version, BasicVersionedJvmClassBundle::new);

					// Handle duplicate classes
					JvmClassInfo existingClass = bundle.get(className);
					if (existingClass != null) {
						deduplicateClass(existingClass, classInfo, bundle, files);
					} else {
						VersionedClassProperty.set(classInfo, version);
						bundle.initialPut(classInfo);
					}
				} catch (NumberFormatException ex) {
					// Version is invalid, record it as a file instead.
					logger.warn("Class entry seemed to be for multi-release jar, " +
							"but version is non-numeric value: " + versionName);

					// Override the prior value.
					// The JVM always selects the last option if there are duplicates.
					files.initialPut(new FileInfoBuilder<>()
							.withName(pathName)
							.withRawContent(classInfo.getBytecode())
							.build());
				} catch (IllegalArgumentException ex) {
					// Class name doesn't match what is declared locally in the versioned folder.
					logger.warn("Class entry seemed to be for multi-release jar, " +
							"but the name doesn't align with the declared type: " + pathName);

					// Override the prior value.
					// The JVM always selects the last option if there are duplicates.
					files.initialPut(new FileInfoBuilder<>()
							.withName(pathName)
							.withRawContent(classInfo.getBytecode())
							.build());
				}
				return;
			}

			// Handle duplicate classes
			JvmClassInfo existingClass = classes.get(className);
			if (existingClass != null) {
				deduplicateClass(existingClass, classInfo, classes, files);
			} else {
				classes.initialPut(classInfo);
			}
		} else if (info.isFile()) {
			FileInfo fileInfo = info.asFile();

			// Check for special file cases (Currently just DEX)
			if (fileInfo instanceof DexFileInfo) {
				try {
					AndroidClassBundle dexBundle = DexIOUtil.read(infoSource);
					androidClassBundles.put(pathName, dexBundle);
				} catch (IOException ex) {
					logger.error("Failed to read embedded DEX '{}'", pathName, ex);
					files.initialPut(fileInfo);
				}
				return;
			}

			// Check for container file cases (Any ZIP type, JAR/WAR/etc)
			if (fileInfo.isZipFile()) {
				try {
					WorkspaceFileResourceBuilder embeddedResourceBuilder = new WorkspaceFileResourceBuilder()
							.withFileInfo(fileInfo);
					WorkspaceFileResource embeddedResource = handleZip(embeddedResourceBuilder,
							fileInfo.asZipFile(), infoSource);
					embeddedResources.put(pathName, embeddedResource);
				} catch (IOException ex) {
					logger.error("Failed to read embedded ZIP '{}'", pathName, ex);
					files.initialPut(fileInfo);
				}
				return;
			}

			// Check for other edge case types containing embedded content.
			if (fileInfo instanceof ModulesFileInfo) {
				try {
					WorkspaceResourceBuilder embeddedResourceBuilder = new WorkspaceResourceBuilder()
							.withFileInfo(fileInfo);
					WorkspaceFileResource embeddedResource =
							(WorkspaceFileResource) handleModules(embeddedResourceBuilder, (ModulesFileInfo) fileInfo);
					embeddedResources.put(pathName, embeddedResource);
				} catch (IOException ex) {
					logger.error("Failed to read embedded ZIP '{}'", pathName, ex);
					files.initialPut(fileInfo);
				}
				return;
			}

			// Warn if there are duplicate file entries.
			// Same cases for why this may occur are described above when handling classes.
			// The JVM will always use the last item for duplicate entries anyways.
			if (files.containsKey(pathName)) {
				logger.warn("Multiple duplicate entries for file '{}', dropping older entry", pathName);
			}

			// Store in bundle.
			files.initialPut(fileInfo);
		} else {
			throw new IllegalStateException("Unknown info type: " + info);
		}
	}
General read handling for any single-file resource kind. Delegates to others when needed.

@param builder
		Builder to work with.
@param pathName
		Name of input file / content.
@param source
		Access to content / data.

@return Read resource.
recaf-core/src/main/java/software/coley/recaf/services/workspace/io/BasicResourceImporter.java