private SymbolFileLocation ensureLocalUncompressedFile(SymbolFileLocation symbolFileLocation,
			TaskMonitor monitor) throws IOException, CancelledException {
		if (!(symbolFileLocation.getSymbolServer() instanceof SymbolStore)) {
			symbolFileLocation = copyRemoteToLocal(symbolFileLocation, monitor);
		}

		// symbolFileLocation now must be on a SymbolStore, so safe to cast
		SymbolStore localSymbolStore = (SymbolStore) symbolFileLocation.getSymbolServer();

		if (SymbolStore.isCompressedFilename(symbolFileLocation.getPath())) {
			File cabFile = localSymbolStore.getFile(symbolFileLocation.getPath());
			File adminDir = symbolStore.getAdminDir();
			if (!adminDir.isDirectory()) {
				// if the admin dir is missing, use the cab file's directory
				adminDir = cabFile.getParentFile();
			}
			File temporaryExtractFile =
				new File(adminDir, "ghidra_cab_extract_tmp_" + System.currentTimeMillis());

			Msg.debug(this, "%s: decompressing file %s".formatted(logPrefix(),
				symbolFileLocation.getLocationStr()));

			String originalName =
				PdbUtils.extractSingletonCabToFile(cabFile, temporaryExtractFile, monitor);
			String uncompressedPath =
				symbolStore.giveFile(symbolFileLocation.getFileInfo(), temporaryExtractFile,
					originalName, monitor);

			symbolFileLocation = new SymbolFileLocation(uncompressedPath, symbolStore,
				symbolFileLocation.getFileInfo());

			Msg.debug(this, "%s: new decompressed file %s".formatted(logPrefix(),
				symbolFileLocation.getLocationStr()));
		}

		return symbolFileLocation;
	}
Converts a possibly remote {@link SymbolFileLocation} to a location that is local and
uncompressed.

@param symbolFileLocation possibly remote {@link SymbolFileLocation}
@param monitor {@link TaskMonitor} to display progress and allow canceling
@return {@link SymbolFileLocation} that is local (possibly the same  instance if already
local)
@throws CancelledException if canceled
@throws IOException if error
Ghidra/Features/PDB/src/main/java/pdb/symbolserver/SymbolServerService.java