import type common from "@ohos:app.ability.common";
import type webview from "@ohos:web.webview";
import request from "@ohos:request";
import fs from "@ohos:file.fs";
import picker from "@ohos:file.picker";
import type { OnSdkEvent } from '../model/SignCallback';
import { DownloadStartEvent, DownloadFailedEvent, DownloadCompletedEvent } from "@normalized:N&&&tencentqianwebview/src/main/ets/model/SdkEvent&1.0.0";
class BjcCov {
    coverage: {
        [key: string]: string | number;
    };
    constructor(covData: object) {
        const gcv = "__coverage__";
        let coverage = globalThis[gcv] || (globalThis[gcv] = {});
        if (!coverage[covData.path] && true) {
            coverage[covData.path] = covData;
        }
        this.coverage = coverage[covData.path];
    }
    instrumentFunction(func: number) {
        this.coverage.functions[func].count++;
        this.coverage.functions[func].regions[0].count++;
    }
    instrumentRegion(func: number, region: number) {
        this.coverage.functions[func].regions[region].count++;
        /** SDK 缓存子目录名。 */
    }
    instrumentReturn(func: number, retIdx: number) {
        this.coverage.functions[func].returnes[retIdx].count++;
    }
    instrumentBranch(func: number, branch: number, trueOrFalse: boolean) {
        if (trueOrFalse) {
            this.coverage.functions[func].branches[branch].trueCount++;
            for (let r of Object.values(this.coverage.functions[func].branches[branch].group)) {
                if (r !== branch) {
                    this.coverage.functions[func].branches[r as number].falseCount++;
                }
            }
        }
        else {
            this.coverage.functions[func].branches[branch].falseCount++;
        }
    }
}
let bjccovms5u83om = new BjcCov({ version: "bjc v1.0.0", versionCode: 10000, path: "tencentqianwebview/src/main/ets/internal/DownloadHandler.ets", hash: "6ac36530791ca8e95a974a3b6a9afe04ffdb917cbd48af4c63fdaac51b4ecf5a", lineCnt: 252, count: 0, projectPath: "", functions: { 0: { name: "DownloadHandler.start", count: 0, regions: { 0: { startLoc: { line: 31, col: 3 }, endLoc: { line: 97, col: 4 }, count: 0, ignored: 0 }, 1: { startLoc: { line: 39, col: 64 }, endLoc: { line: 41, col: 6 }, count: 0, ignored: 0 }, 2: { startLoc: { line: 43, col: 37 }, endLoc: { line: 47, col: 6 }, count: 0, ignored: 0 }, 3: { startLoc: { line: 51, col: 76 }, endLoc: { line: 54, col: 6 }, count: 0, ignored: 0 }, 4: { startLoc: { line: 59, col: 32 }, endLoc: { line: 61, col: 6 }, count: 0, ignored: 0 }, 5: { startLoc: { line: 67, col: 9 }, endLoc: { line: 71, col: 6 }, count: 0, ignored: 0 }, 6: { startLoc: { line: 71, col: 7 }, endLoc: { line: 72, col: 6 }, count: 0, ignored: 0 }, 7: { startLoc: { line: 68, col: 36 }, endLoc: { line: 70, col: 8 }, count: 0, ignored: 0 }, 8: { startLoc: { line: 74, col: 9 }, endLoc: { line: 91, col: 6 }, count: 0, ignored: 0 }, 9: { startLoc: { line: 91, col: 7 }, endLoc: { line: 96, col: 6 }, count: 0, ignored: 0 } }, branches: { 0: { startLoc: { line: 39, col: 9 }, endLoc: { line: 39, col: 62 }, trueCount: 0, falseCount: 0, group: {}, ignored: 0 }, 1: { startLoc: { line: 43, col: 9 }, endLoc: { line: 43, col: 35 }, trueCount: 0, falseCount: 0, group: {}, ignored: 0 }, 2: { startLoc: { line: 51, col: 9 }, endLoc: { line: 51, col: 74 }, trueCount: 0, falseCount: 0, group: {}, ignored: 0 }, 3: { startLoc: { line: 56, col: 30 }, endLoc: { line: 56, col: 89 }, trueCount: 0, falseCount: 0, group: {}, ignored: 0 }, 4: { startLoc: { line: 57, col: 28 }, endLoc: { line: 57, col: 117 }, trueCount: 0, falseCount: 0, group: {}, ignored: 0 }, 5: { startLoc: { line: 59, col: 9 }, endLoc: { line: 59, col: 30 }, trueCount: 0, falseCount: 0, group: {}, ignored: 0 }, 6: { startLoc: { line: 68, col: 11 }, endLoc: { line: 68, col: 34 }, trueCount: 0, falseCount: 0, group: {}, ignored: 0 }, 7: { startLoc: { line: 92, col: 30 }, endLoc: { line: 94, col: 20 }, trueCount: 0, falseCount: 0, group: {}, ignored: 0 } }, ignored: 0, index: 0 }, 1: { name: "anonymous_0", count: 0, regions: { 0: { startLoc: { line: 85, col: 27 }, endLoc: { line: 87, col: 8 }, count: 0, ignored: 0 }, 1: { startLoc: { line: 86, col: 9 }, endLoc: { line: 87, col: 8 }, count: 0, ignored: 0 } }, branches: {}, ignored: 0, index: 1 }, 2: { name: "anonymous_1", count: 0, regions: { 0: { startLoc: { line: 88, col: 23 }, endLoc: { line: 90, col: 8 }, count: 0, ignored: 0 }, 1: { startLoc: { line: 89, col: 9 }, endLoc: { line: 90, col: 8 }, count: 0, ignored: 0 } }, branches: {}, ignored: 0, index: 2 }, 3: { name: "DownloadHandler.resolveFilename", count: 0, regions: { 0: { startLoc: { line: 102, col: 3 }, endLoc: { line: 112, col: 4 }, count: 0, ignored: 0 }, 1: { startLoc: { line: 104, col: 28 }, endLoc: { line: 106, col: 6 }, count: 0, ignored: 0 }, 2: { startLoc: { line: 108, col: 29 }, endLoc: { line: 110, col: 6 }, count: 0, ignored: 0 }, 3: { startLoc: { line: 111, col: 5 }, endLoc: { line: 112, col: 4 }, count: 0, ignored: 0 } }, branches: { 0: { startLoc: { line: 104, col: 9 }, endLoc: { line: 104, col: 26 }, trueCount: 0, falseCount: 0, group: {}, ignored: 0 }, 1: { startLoc: { line: 108, col: 9 }, endLoc: { line: 108, col: 27 }, trueCount: 0, falseCount: 0, group: {}, ignored: 0 } }, ignored: 0, index: 3 }, 4: { name: "DownloadHandler.parseFilenameFromCd", count: 0, regions: { 0: { startLoc: { line: 114, col: 3 }, endLoc: { line: 132, col: 4 }, count: 0, ignored: 0 }, 1: { startLoc: { line: 115, col: 61 }, endLoc: { line: 117, col: 6 }, count: 0, ignored: 0 }, 2: { startLoc: { line: 120, col: 53 }, endLoc: { line: 125, col: 6 }, count: 0, ignored: 0 }, 3: { startLoc: { line: 121, col: 11 }, endLoc: { line: 123, col: 8 }, count: 0, ignored: 0 }, 4: { startLoc: { line: 123, col: 9 }, endLoc: { line: 124, col: 8 }, count: 0, ignored: 0 }, 5: { startLoc: { line: 128, col: 45 }, endLoc: { line: 130, col: 6 }, count: 0, ignored: 0 }, 6: { startLoc: { line: 131, col: 5 }, endLoc: { line: 132, col: 4 }, count: 0, ignored: 0 } }, branches: { 0: { startLoc: { line: 115, col: 9 }, endLoc: { line: 115, col: 59 }, trueCount: 0, falseCount: 0, group: {}, ignored: 0 }, 1: { startLoc: { line: 120, col: 9 }, endLoc: { line: 120, col: 51 }, trueCount: 0, falseCount: 0, group: {}, ignored: 0 }, 2: { startLoc: { line: 128, col: 9 }, endLoc: { line: 128, col: 43 }, trueCount: 0, falseCount: 0, group: {}, ignored: 0 } }, ignored: 0, index: 4 }, 5: { name: "DownloadHandler.parseFilenameFromUrl", count: 0, regions: { 0: { startLoc: { line: 134, col: 3 }, endLoc: { line: 145, col: 4 }, count: 0, ignored: 0 }, 1: { startLoc: { line: 135, col: 9 }, endLoc: { line: 142, col: 6 }, count: 0, ignored: 0 }, 2: { startLoc: { line: 142, col: 7 }, endLoc: { line: 144, col: 6 }, count: 0, ignored: 0 }, 3: { startLoc: { line: 138, col: 50 }, endLoc: { line: 140, col: 8 }, count: 0, ignored: 0 }, 4: { startLoc: { line: 141, col: 7 }, endLoc: { line: 142, col: 6 }, count: 0, ignored: 0 } }, branches: { 0: { startLoc: { line: 138, col: 11 }, endLoc: { line: 138, col: 48 }, trueCount: 0, falseCount: 0, group: {}, ignored: 0 } }, ignored: 0, index: 5 }, 6: { name: "DownloadHandler.sanitize", count: 0, regions: { 0: { startLoc: { line: 147, col: 3 }, endLoc: { line: 159, col: 4 }, count: 0, ignored: 0 }, 1: { startLoc: { line: 151, col: 52 }, endLoc: { line: 153, col: 6 }, count: 0, ignored: 0 }, 2: { startLoc: { line: 155, col: 25 }, endLoc: { line: 157, col: 6 }, count: 0, ignored: 0 }, 3: { startLoc: { line: 158, col: 5 }, endLoc: { line: 159, col: 4 }, count: 0, ignored: 0 } }, branches: { 0: { startLoc: { line: 151, col: 9 }, endLoc: { line: 151, col: 50 }, trueCount: 0, falseCount: 0, group: {}, ignored: 0 }, 1: { startLoc: { line: 155, col: 9 }, endLoc: { line: 155, col: 23 }, trueCount: 0, falseCount: 0, group: {}, ignored: 0 } }, ignored: 0, index: 6 }, 7: { name: "DownloadHandler.ensureSavePath", count: 0, regions: { 0: { startLoc: { line: 161, col: 3 }, endLoc: { line: 177, col: 4 }, count: 0, ignored: 0 }, 1: { startLoc: { line: 163, col: 9 }, endLoc: { line: 167, col: 6 }, count: 0, ignored: 0 }, 2: { startLoc: { line: 167, col: 7 }, endLoc: { line: 168, col: 6 }, count: 0, ignored: 0 }, 3: { startLoc: { line: 164, col: 32 }, endLoc: { line: 166, col: 8 }, count: 0, ignored: 0 }, 4: { startLoc: { line: 173, col: 41 }, endLoc: { line: 175, col: 6 }, count: 0, ignored: 0 }, 5: { startLoc: { line: 176, col: 5 }, endLoc: { line: 177, col: 4 }, count: 0, ignored: 0 } }, branches: { 0: { startLoc: { line: 164, col: 11 }, endLoc: { line: 164, col: 30 }, trueCount: 0, falseCount: 0, group: {}, ignored: 0 }, 1: { startLoc: { line: 172, col: 9 }, endLoc: { line: 173, col: 39 }, trueCount: 0, falseCount: 0, group: {}, ignored: 0 } }, ignored: 0, index: 7 }, 8: { name: "DownloadHandler.emitFailed", count: 0, regions: { 0: { startLoc: { line: 179, col: 3 }, endLoc: { line: 183, col: 4 }, count: 0, ignored: 0 }, 1: { startLoc: { line: 180, col: 32 }, endLoc: { line: 182, col: 6 }, count: 0, ignored: 0 } }, branches: { 0: { startLoc: { line: 180, col: 9 }, endLoc: { line: 180, col: 30 }, trueCount: 0, falseCount: 0, group: {}, ignored: 0 } }, ignored: 0, index: 8 }, 9: { name: "DownloadHandler.saveToUserPicked", count: 0, regions: { 0: { startLoc: { line: 192, col: 3 }, endLoc: { line: 248, col: 4 }, count: 0, ignored: 0 }, 1: { startLoc: { line: 199, col: 9 }, endLoc: { line: 207, col: 6 }, count: 0, ignored: 0 }, 2: { startLoc: { line: 207, col: 7 }, endLoc: { line: 208, col: 6 }, count: 0, ignored: 0 }, 3: { startLoc: { line: 204, col: 67 }, endLoc: { line: 206, col: 8 }, count: 0, ignored: 0 }, 4: { startLoc: { line: 210, col: 33 }, endLoc: { line: 215, col: 6 }, count: 0, ignored: 0 }, 5: { startLoc: { line: 211, col: 34 }, endLoc: { line: 213, col: 8 }, count: 0, ignored: 0 }, 6: { startLoc: { line: 219, col: 9 }, endLoc: { line: 236, col: 6 }, count: 0, ignored: 0 }, 7: { startLoc: { line: 236, col: 7 }, endLoc: { line: 247, col: 6 }, count: 0, ignored: 0 }, 8: { startLoc: { line: 229, col: 11 }, endLoc: { line: 231, col: 8 }, count: 0, ignored: 0 }, 9: { startLoc: { line: 231, col: 9 }, endLoc: { line: 232, col: 8 }, count: 0, ignored: 0 }, 10: { startLoc: { line: 233, col: 34 }, endLoc: { line: 235, col: 8 }, count: 0, ignored: 0 }, 11: { startLoc: { line: 237, col: 23 }, endLoc: { line: 239, col: 8 }, count: 0, ignored: 0 }, 12: { startLoc: { line: 238, col: 13 }, endLoc: { line: 238, col: 37 }, count: 0, ignored: 0 }, 13: { startLoc: { line: 238, col: 38 }, endLoc: { line: 238, col: 51 }, count: 0, ignored: 0 }, 14: { startLoc: { line: 240, col: 24 }, endLoc: { line: 242, col: 8 }, count: 0, ignored: 0 }, 15: { startLoc: { line: 241, col: 13 }, endLoc: { line: 241, col: 38 }, count: 0, ignored: 0 }, 16: { startLoc: { line: 241, col: 39 }, endLoc: { line: 241, col: 52 }, count: 0, ignored: 0 }, 17: { startLoc: { line: 214, col: 7 }, endLoc: { line: 215, col: 6 }, count: 0, ignored: 0 }, 18: { startLoc: { line: 243, col: 7 }, endLoc: { line: 247, col: 6 }, count: 0, ignored: 0 } }, branches: { 0: { startLoc: { line: 204, col: 11 }, endLoc: { line: 204, col: 65 }, trueCount: 0, falseCount: 0, group: {}, ignored: 0 }, 1: { startLoc: { line: 210, col: 9 }, endLoc: { line: 210, col: 31 }, trueCount: 0, falseCount: 0, group: {}, ignored: 0 }, 2: { startLoc: { line: 211, col: 11 }, endLoc: { line: 211, col: 32 }, trueCount: 0, falseCount: 0, group: {}, ignored: 0 }, 3: { startLoc: { line: 233, col: 11 }, endLoc: { line: 233, col: 32 }, trueCount: 0, falseCount: 0, group: {}, ignored: 0 }, 4: { startLoc: { line: 237, col: 11 }, endLoc: { line: 237, col: 21 }, trueCount: 0, falseCount: 0, group: {}, ignored: 0 }, 5: { startLoc: { line: 240, col: 11 }, endLoc: { line: 240, col: 22 }, trueCount: 0, falseCount: 0, group: {}, ignored: 0 }, 6: { startLoc: { line: 243, col: 30 }, endLoc: { line: 245, col: 20 }, trueCount: 0, falseCount: 0, group: {}, ignored: 0 } }, ignored: 0, index: 9 }, 10: { name: "DownloadHandler.constructor", count: 0, regions: { 0: { startLoc: { line: 250, col: 3 }, endLoc: { line: 250, col: 27 }, count: 0, ignored: 0 } }, branches: {}, ignored: 0, index: 10 } }, exeLine: { 0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 17, 8: 19, 9: 31, 10: 32, 11: 33, 12: 34, 13: 35, 14: 36, 15: 37, 16: 38, 17: 39, 18: 40, 19: 43, 20: 44, 21: 45, 22: 46, 23: 50, 24: 51, 25: 52, 26: 53, 27: 56, 28: 57, 29: 59, 30: 60, 31: 63, 32: 64, 33: 67, 34: 68, 35: 69, 36: 71, 37: 74, 38: 75, 39: 76, 40: 77, 41: 78, 42: 79, 43: 80, 44: 81, 45: 83, 46: 85, 47: 86, 48: 88, 49: 89, 50: 91, 51: 92, 52: 93, 53: 94, 54: 95, 55: 102, 56: 103, 57: 104, 58: 105, 59: 107, 60: 108, 61: 109, 62: 111, 63: 114, 64: 115, 65: 116, 66: 119, 67: 120, 68: 121, 69: 122, 70: 123, 71: 127, 72: 128, 73: 129, 74: 131, 75: 134, 76: 135, 77: 136, 78: 137, 79: 138, 80: 139, 81: 141, 82: 142, 83: 143, 84: 147, 85: 149, 86: 151, 87: 152, 88: 155, 89: 156, 90: 158, 91: 161, 92: 162, 93: 163, 94: 164, 95: 165, 96: 167, 97: 171, 98: 172, 99: 173, 100: 174, 101: 176, 102: 179, 103: 180, 104: 181, 105: 192, 106: 193, 107: 194, 108: 195, 109: 196, 110: 197, 111: 198, 112: 199, 113: 200, 114: 201, 115: 202, 116: 203, 117: 204, 118: 205, 119: 207, 120: 210, 121: 211, 122: 212, 123: 214, 124: 217, 125: 218, 126: 219, 127: 220, 128: 221, 129: 222, 130: 223, 131: 224, 132: 225, 133: 226, 134: 227, 135: 228, 136: 229, 137: 230, 138: 231, 139: 233, 140: 234, 141: 236, 142: 237, 143: 238, 144: 240, 145: 241, 146: 243, 147: 244, 148: 245, 149: 246, 150: 250 } });
/**
 * 下载处理器。
 *
 * 通过 `@ohos.request.downloadFile` 把 http(s) 下载链接落到 app 沙箱缓存目录,
 * 再调用 `DocumentViewPicker.save` 让用户选择目标位置完成另存。
 *
 * 不支持 `blob:` 协议,触发时 emit `DownloadFailed`,由集成方通过 JSBridge 实现。
 */
export class DownloadHandler {
    /** SDK 缓存子目录名。 */
    private static readonly CACHE_SUBDIR: string = 'qian-download';
    /**
     * 触发下载。
     *
     * @param controller WebviewController(预留参数,本实现未使用)
     * @param context UIAbility/页面 context
     * @param url 下载 URL
     * @param mimeType MIME 类型
     * @param contentDisposition Content-Disposition 头
     * @param onEvent 可选的事件回调
     */
    public static async start(controller: webview.WebviewController, context: common.UIAbilityContext, url: string, mimeType: string, contentDisposition: string, onEvent?: OnSdkEvent): Promise<void> {
        bjccovms5u83om.instrumentFunction(0);
        if (url === null || url === undefined || url.length === 0) {
            bjccovms5u83om.instrumentBranch(0, 0, true);
            bjccovms5u83om.instrumentRegion(0, 1);
            return;
        }
        else {
            bjccovms5u83om.instrumentBranch(0, 0, false);
        }
        if (url.indexOf('blob:') === 0) {
            bjccovms5u83om.instrumentBranch(0, 1, true);
            bjccovms5u83om.instrumentRegion(0, 2);
            DownloadHandler.emitFailed(onEvent, url, 'blob 下载暂不支持,请通过 JSBridge 自行实现');
            return;
        }
        // 仅处理 http(s)
        else {
            bjccovms5u83om.instrumentBranch(0, 1, false);
        }
        // 仅处理 http(s)
        const lower: string = url.toLowerCase();
        if (lower.indexOf('http://') !== 0 && lower.indexOf('https://') !== 0) {
            bjccovms5u83om.instrumentBranch(0, 2, true);
            bjccovms5u83om.instrumentRegion(0, 3);
            DownloadHandler.emitFailed(onEvent, url, '不支持的下载协议');
            return;
        }
        else {
            bjccovms5u83om.instrumentBranch(0, 2, false);
        }
        const safeMime: string = mimeType === null || mimeType === undefined ? (bjccovms5u83om.instrumentBranch(0, 3, true), '') : (bjccovms5u83om.instrumentBranch(0, 3, false), mimeType);
        const safeCd: string = contentDisposition === null || contentDisposition === undefined ? (bjccovms5u83om.instrumentBranch(0, 4, true), '') : (bjccovms5u83om.instrumentBranch(0, 4, false), contentDisposition);
        if (onEvent !== undefined) {
            bjccovms5u83om.instrumentBranch(0, 5, true);
            bjccovms5u83om.instrumentRegion(0, 4);
            onEvent(new DownloadStartEvent(url, safeMime, safeCd));
        }
        else {
            bjccovms5u83om.instrumentBranch(0, 5, false);
        }
        const filename: string = DownloadHandler.resolveFilename(url, safeCd);
        const savePath: string = DownloadHandler.ensureSavePath(context, filename);
        // request.downloadFile 不支持 overwrite,目标已存在会 reject(13400002),先清理
        try {
            bjccovms5u83om.instrumentRegion(0, 5);
            if (fs.accessSync(savePath)) {
                bjccovms5u83om.instrumentBranch(0, 6, true);
                bjccovms5u83om.instrumentRegion(0, 7);
                fs.unlinkSync(savePath);
            }
            else {
                bjccovms5u83om.instrumentBranch(0, 6, false);
            }
        }
        catch (_e) {
            bjccovms5u83om.instrumentRegion(0, 6);
        }
        try {
            bjccovms5u83om.instrumentRegion(0, 8);
            const cfg: request.DownloadConfig = {
                url: url,
                filePath: savePath,
                enableMetered: true,
                enableRoaming: true,
                description: filename,
                title: filename
            };
            const task: request.DownloadTask = await request.downloadFile(context, cfg);
            task.on('complete', (): void => {
                bjccovms5u83om.instrumentFunction(1);
                bjccovms5u83om.instrumentRegion(1, 1);
                DownloadHandler.saveToUserPicked(savePath, filename, url, onEvent);
            });
            task.on('fail', (err: number): void => {
                bjccovms5u83om.instrumentFunction(2);
                bjccovms5u83om.instrumentRegion(2, 1);
                DownloadHandler.emitFailed(onEvent, url, '下载失败 errCode=' + err.toString());
            });
        }
        catch (e) {
            bjccovms5u83om.instrumentRegion(0, 9);
            const reason: string = (e instanceof Error)
                ? (bjccovms5u83om.instrumentBranch(0, 7, true), (e.name + ': ' + e.message)) : (bjccovms5u83om.instrumentBranch(0, 7, false), String(e));
            DownloadHandler.emitFailed(onEvent, url, '下载启动失败: ' + reason);
        }
    }
    /**
     * 计算落盘文件名: Content-Disposition > URL 末段 > 时间戳兜底。
     */
    private static resolveFilename(url: string, contentDisposition: string): string {
        bjccovms5u83om.instrumentFunction(3);
        const fromCd: string = DownloadHandler.parseFilenameFromCd(contentDisposition);
        if (fromCd.length > 0) {
            bjccovms5u83om.instrumentBranch(3, 0, true);
            bjccovms5u83om.instrumentRegion(3, 1);
            return DownloadHandler.sanitize(fromCd);
        }
        else {
            bjccovms5u83om.instrumentBranch(3, 0, false);
        }
        const fromUrl: string = DownloadHandler.parseFilenameFromUrl(url);
        if (fromUrl.length > 0) {
            bjccovms5u83om.instrumentBranch(3, 1, true);
            bjccovms5u83om.instrumentRegion(3, 2);
            return DownloadHandler.sanitize(fromUrl);
        }
        else {
            bjccovms5u83om.instrumentBranch(3, 1, false);
        }
        bjccovms5u83om.instrumentRegion(3, 3);
        return 'download_' + Date.now().toString();
    }
    private static parseFilenameFromCd(cd: string): string {
        bjccovms5u83om.instrumentFunction(4);
        if (cd === null || cd === undefined || cd.length === 0) {
            bjccovms5u83om.instrumentBranch(4, 0, true);
            bjccovms5u83om.instrumentRegion(4, 1);
            return '';
        }
        // RFC 5987: filename*=UTF-8''xxxx
        else {
            bjccovms5u83om.instrumentBranch(4, 0, false);
        }
        // RFC 5987: filename*=UTF-8''xxxx
        const starMatch = cd.match(/filename\*\s*=\s*[^']*''([^;]+)/i);
        if (starMatch !== null && starMatch.length > 1) {
            bjccovms5u83om.instrumentBranch(4, 1, true);
            bjccovms5u83om.instrumentRegion(4, 2);
            try {
                bjccovms5u83om.instrumentRegion(4, 3);
                return decodeURIComponent(starMatch[1].trim());
            }
            catch (_e) {
                bjccovms5u83om.instrumentRegion(4, 4);
            }
        }
        // filename="xxxx" 或 filename=xxxx
        else {
            bjccovms5u83om.instrumentBranch(4, 1, false);
        }
        // filename="xxxx" 或 filename=xxxx
        const plain = cd.match(/filename\s*=\s*"?([^";]+)"?/i);
        if (plain !== null && plain.length > 1) {
            bjccovms5u83om.instrumentBranch(4, 2, true);
            bjccovms5u83om.instrumentRegion(4, 5);
            return plain[1].trim();
        }
        else {
            bjccovms5u83om.instrumentBranch(4, 2, false);
        }
        bjccovms5u83om.instrumentRegion(4, 6);
        return '';
    }
    private static parseFilenameFromUrl(url: string): string {
        bjccovms5u83om.instrumentFunction(5);
        try {
            bjccovms5u83om.instrumentRegion(5, 1);
            const noQuery: string = url.split('?')[0].split('#')[0];
            const idx: number = noQuery.lastIndexOf('/');
            if (idx < 0 || idx === noQuery.length - 1) {
                bjccovms5u83om.instrumentBranch(5, 0, true);
                bjccovms5u83om.instrumentRegion(5, 3);
                return '';
            }
            else {
                bjccovms5u83om.instrumentBranch(5, 0, false);
            }
            bjccovms5u83om.instrumentRegion(5, 4);
            return decodeURIComponent(noQuery.substring(idx + 1));
        }
        catch (_e) {
            bjccovms5u83om.instrumentRegion(5, 2);
            return '';
        }
    }
    private static sanitize(name: string): string {
        bjccovms5u83om.instrumentFunction(6);
        // 过滤路径分隔符/非法字符与上跳段，防路径穿越。
        let n: string = name.replace(/[\\/:*?"<>|]/g, '_').replace(/\.\./g, '_').trim();
        // 兜底：清洗后为空 / 纯 "." / 纯 ".." → 时间戳默认名，避免产生指向目录本身的无效路径。
        if (n.length === 0 || n === '.' || n === '..') {
            bjccovms5u83om.instrumentBranch(6, 0, true);
            bjccovms5u83om.instrumentRegion(6, 1);
            n = 'download_' + Date.now().toString();
        }
        // 限长，防超长名写入失败。
        else {
            bjccovms5u83om.instrumentBranch(6, 0, false);
        }
        // 限长，防超长名写入失败。
        if (n.length > 200) {
            bjccovms5u83om.instrumentBranch(6, 1, true);
            bjccovms5u83om.instrumentRegion(6, 2);
            n = n.substring(n.length - 200);
        }
        else {
            bjccovms5u83om.instrumentBranch(6, 1, false);
        }
        bjccovms5u83om.instrumentRegion(6, 3);
        return n;
    }
    private static ensureSavePath(context: common.UIAbilityContext, filename: string): string {
        bjccovms5u83om.instrumentFunction(7);
        const dir: string = context.cacheDir + '/' + DownloadHandler.CACHE_SUBDIR;
        try {
            bjccovms5u83om.instrumentRegion(7, 1);
            if (!fs.accessSync(dir)) {
                bjccovms5u83om.instrumentBranch(7, 0, true);
                bjccovms5u83om.instrumentRegion(7, 3);
                fs.mkdirSync(dir, true);
            }
            else {
                bjccovms5u83om.instrumentBranch(7, 0, false);
            }
        }
        catch (_e) {
            bjccovms5u83om.instrumentRegion(7, 2);
        }
        // 落盘二次防御：即便 sanitize 被绕过，文件名仍不得含路径分隔符/上跳段，
        // 否则用时间戳兜底名，确保写入路径始终落在缓存子目录内（不逃逸）。
        let safe: string = filename;
        if (safe.length === 0 || safe.indexOf('/') >= 0 || safe.indexOf('\\') >= 0
            || safe === '.' || safe === '..') {
            bjccovms5u83om.instrumentBranch(7, 1, true);
            bjccovms5u83om.instrumentRegion(7, 4);
            safe = 'download_' + Date.now().toString();
        }
        else {
            bjccovms5u83om.instrumentBranch(7, 1, false);
        }
        bjccovms5u83om.instrumentRegion(7, 5);
        return dir + '/' + safe;
    }
    private static emitFailed(onEvent: OnSdkEvent | undefined, url: string, reason: string): void {
        bjccovms5u83om.instrumentFunction(8);
        if (onEvent !== undefined) {
            bjccovms5u83om.instrumentBranch(8, 0, true);
            bjccovms5u83om.instrumentRegion(8, 1);
            onEvent(new DownloadFailedEvent(url, reason));
        }
        else /**
         * 弹 `DocumentViewPicker.save` 让用户选择目标位置,把缓存文件拷贝过去。
         *
         * - 用户选定: 拷贝到目标 uri,清理缓存,emit `DownloadCompleted(url, 目标 uri)`
         * - 用户取消或 picker 异常: emit `DownloadCompleted(url, 缓存路径)`,缓存保留
         * - 拷贝失败: emit `DownloadFailed`
         */ {
            bjccovms5u83om.instrumentBranch(8, 0, false);
        }
    }
    /**
     * 弹 `DocumentViewPicker.save` 让用户选择目标位置,把缓存文件拷贝过去。
     *
     * - 用户选定: 拷贝到目标 uri,清理缓存,emit `DownloadCompleted(url, 目标 uri)`
     * - 用户取消或 picker 异常: emit `DownloadCompleted(url, 缓存路径)`,缓存保留
     * - 拷贝失败: emit `DownloadFailed`
     */
    private static async saveToUserPicked(cachePath: string, filename: string, url: string, onEvent: OnSdkEvent | undefined): Promise<void> {
        bjccovms5u83om.instrumentFunction(9);
        let targetUri: string = '';
        try {
            bjccovms5u83om.instrumentRegion(9, 1);
            const documentPicker = new picker.DocumentViewPicker();
            const opts: picker.DocumentSaveOptions = new picker.DocumentSaveOptions();
            opts.newFileNames = [filename];
            const uris: string[] = await documentPicker.save(opts);
            if (uris !== null && uris !== undefined && uris.length > 0) {
                bjccovms5u83om.instrumentBranch(9, 0, true);
                bjccovms5u83om.instrumentRegion(9, 3);
                targetUri = uris[0];
            }
            else {
                bjccovms5u83om.instrumentBranch(9, 0, false);
            }
        }
        catch (_e) {
            bjccovms5u83om.instrumentRegion(9, 2);
        }
        if (targetUri.length === 0) {
            bjccovms5u83om.instrumentBranch(9, 1, true);
            bjccovms5u83om.instrumentRegion(9, 4);
            if (onEvent !== undefined) {
                bjccovms5u83om.instrumentBranch(9, 2, true);
                bjccovms5u83om.instrumentRegion(9, 5);
                onEvent(new DownloadCompletedEvent(url, cachePath));
            }
            else {
                bjccovms5u83om.instrumentBranch(9, 2, false);
            }
            bjccovms5u83om.instrumentRegion(9, 17);
            return;
        }
        else {
            bjccovms5u83om.instrumentBranch(9, 1, false);
        }
        let destFd: number = -1;
        let srcFd: number = -1;
        try {
            bjccovms5u83om.instrumentRegion(9, 6);
            const destFile = fs.openSync(targetUri, fs.OpenMode.WRITE_ONLY | fs.OpenMode.TRUNC);
            destFd = destFile.fd;
            const srcFile = fs.openSync(cachePath, fs.OpenMode.READ_ONLY);
            srcFd = srcFile.fd;
            fs.copyFileSync(srcFd, destFd);
            fs.closeSync(srcFile);
            srcFd = -1;
            fs.closeSync(destFile);
            destFd = -1;
            try {
                bjccovms5u83om.instrumentRegion(9, 8);
                fs.unlinkSync(cachePath);
            }
            catch (_e) {
                bjccovms5u83om.instrumentRegion(9, 9);
            }
            if (onEvent !== undefined) {
                bjccovms5u83om.instrumentBranch(9, 3, true);
                bjccovms5u83om.instrumentRegion(9, 10);
                onEvent(new DownloadCompletedEvent(url, targetUri));
            }
            else {
                bjccovms5u83om.instrumentBranch(9, 3, false);
            }
        }
        catch (e) {
            bjccovms5u83om.instrumentRegion(9, 7);
            if (srcFd >= 0) {
                bjccovms5u83om.instrumentBranch(9, 4, true);
                bjccovms5u83om.instrumentRegion(9, 11);
                try {
                    bjccovms5u83om.instrumentRegion(9, 12);
                    fs.closeSync(srcFd);
                }
                catch (_e) {
                    bjccovms5u83om.instrumentRegion(9, 13);
                }
            }
            else {
                bjccovms5u83om.instrumentBranch(9, 4, false);
            }
            if (destFd >= 0) {
                bjccovms5u83om.instrumentBranch(9, 5, true);
                bjccovms5u83om.instrumentRegion(9, 14);
                try {
                    bjccovms5u83om.instrumentRegion(9, 15);
                    fs.closeSync(destFd);
                }
                catch (_e) {
                    bjccovms5u83om.instrumentRegion(9, 16);
                }
            }
            else {
                bjccovms5u83om.instrumentBranch(9, 5, false);
            }
            bjccovms5u83om.instrumentRegion(9, 18);
            const reason: string = (e instanceof Error)
                ? (bjccovms5u83om.instrumentBranch(9, 6, true), (e.name + ': ' + e.message)) : (bjccovms5u83om.instrumentBranch(9, 6, false), String(e));
            DownloadHandler.emitFailed(onEvent, url, '保存到所选位置失败: ' + reason);
        }
    }
    private constructor() { bjccovms5u83om.instrumentFunction(10); }
}
