All files / function open.js

88.52% Statements 54/61
82.92% Branches 34/41
77.77% Functions 7/9
87.71% Lines 50/57

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151                                                                                                                          1826x 1826x 1826x 1821x     1826x 1826x 1826x 1826x 1829x     708x   1121x     1826x 1826x 1826x 1826x 1826x 1826x 1826x 1829x 1829x   1829x 1829x 1826x 1826x 1826x 1826x   1826x 1826x 6x 6x 6x 6x   1820x   1820x                     1820x 1820x 1820x 1820x 1820x 1064x 1064x     756x       756x   1820x     1826x   1826x 1826x       1826x 1820x   6x            
/* eslint-disable no-continue */
import { GDALFunctions } from '../../allCFunctions';
import { getGdalError } from '../helper/error';
import { INPUTPATH, OUTPUTPATH } from '../helper/const';
import { mount } from '../helper/filesystem';
import { clearOptions, getOptions } from '../helper/options';
import gdalinfo from '../application/gdalinfo';
import ogrinfo from '../application/ogrinfo';
 
/**
    * Opens files selected with HTML input element.
    *
    * @module f/open
    * @async
    * @param {FileList|File|Array<string>|string} files Returned by the files property of the HTML input element.
    * @param {Array<string>} openOptions Open options passed to candidate drivers.
    * @param {Array<string>} VFSHandlers List of Virtual File System handlers, see https://gdal.org/user/virtual_file_systems.html
    * @return {Promise<TypeDefs.DatasetList>} "Promise" returns dataset list and error list.
    * @example
    * // Opening file from file input.
    * // HTML
    * <input class="input-file" type="file" name="file" id="file" onChange="onFileChange" />
    * // JS
    * function onFileChange({ target }) {
    *   const result = await Gdal.open(target.file);
    * }
    * @example
    * // Opening files from file input. (multiple)
    * // HTML
    * <input class="input-file" type="file" name="files[]" id="file" onChange="onFileChange" multiple />
    * // JS
    * function onFileChange({ target }) {
    *   const result = await Gdal.open(target.files);
    * }
    * @example
    * // Opening a file from the network.
    * const fileData = await fetch('test/polygon.geojson');
    * const file = new File([await fileData.blob()], "polygon.geojson");
    * const result = await Gdal.open(file);
    * @example
    * // Opening a file using the virtual file system handler, ie. /vsicurl/ or /vsizip/.
    * // One common scenario is a .zip shapefile
    * const result = await Gdal.open(file, [], ['vsizip']);
    * @example
    * // Opening a file from filesystem on Node.js.
    * const result = await Gdal.open('test/polygon.geojson');
    * @example
    * // Opening a file from filesystem on Node.js with open options.
    * const result = await Gdal.open('test/points.csv', ['X_POSSIBLE_NAMES=lng', 'Y_POSSIBLE_NAMES=lat']);
    * @example
    * // Opening files from filesystem on Node.js.
    * const result = await Gdal.open(['test/polygon.geojson', 'test/line.geojson']);
    * @example
    * // Opening files from virtual gdal3.js path.
    * // * Opened files are saved in the /input/... virtual path.
    * // * Converted files are saved in the /output/... virtual path.
    * const result = await Gdal.open('/output/polygon.geojson');
    * const result2 = await Gdal.open('/input/polygon.geojson');
    *
*/
export default function open(fileOrFiles, openOptions = [], VFSHandlers = []) {
    let files = fileOrFiles;
    const optStr = getOptions(openOptions);
    if (!(Array.isArray(files) || (typeof FileList === 'function' && files instanceof FileList))) {
        files = [files];
    }
 
    return new Promise((resolve, reject) => {
        const internalFiles = [];
        const externalFiles = [];
        [...files].forEach((file) => {
            if ((typeof file === 'string' || file instanceof String) && (
                file.substring(0, INPUTPATH.length + 1) === `${INPUTPATH}/` || file.substring(0, OUTPUTPATH.length + 1) === `${OUTPUTPATH}/`
            )) {
                internalFiles.push({ name: file.substring(file.indexOf('/', 1) + 1), internal: true, prefix: file.substring(0, file.indexOf('/', 1)) });
            } else {
                externalFiles.push(file);
            }
        });
        mount(externalFiles).then((mountedExternalFiles) => {
            const mountedFiles = [...mountedExternalFiles, ...internalFiles];
            const errors = [];
            GDALFunctions.CPLErrorReset();
            const inputResults = {};
            const promises = [];
            for (let i = 0; i < mountedFiles.length; i += 1) {
                const path = mountedFiles[i].name;
                const name = path.split('.', 1)[0];
 
                if (!inputResults[name]) inputResults[name] = {};
                if (inputResults[name].pointer) continue;
                inputResults[name].path = path;
                const vfsHandlerStr = VFSHandlers && VFSHandlers.length ? `/${VFSHandlers.join('/')}/` : '';
                let fileFullPath = `${vfsHandlerStr}${INPUTPATH}/${path}`;
                if (mountedFiles[i].internal) fileFullPath = `${vfsHandlerStr}${mountedFiles[i].prefix}/${path}`;
 
                const datasetPtr = GDALFunctions.GDALOpenEx(fileFullPath, null, null, optStr.ptr, null);
                if (datasetPtr === 0) {
                    const error = getGdalError();
                    errors.push(error);
                    delete inputResults[name];
                    continue;
                }
                inputResults[name].pointer = datasetPtr;
 
                const setLegacyType = () => {
                    const bandCount = GDALFunctions.GDALGetRasterCount(datasetPtr);
                    const layerCount = GDALFunctions.GDALDatasetGetLayerCount(datasetPtr);
 
                    if (bandCount > 0 && layerCount === 0) {
                        inputResults[name].type = 'raster';
                    } else {
                        inputResults[name].type = 'vector';
                    }
                };
 
                const infoPromise = gdalinfo(inputResults[name]).then((info) => {
                    if (info && info.bands) {
                        const hasSize = info.size && info.size.length >= 2 && (info.size[0] > 0 || info.size[1] > 0);
                        inputResults[name].type = info.bands.length > 0 && hasSize ? 'raster' : 'vector';
                        if (inputResults[name].type === 'vector') {
                            return ogrinfo(inputResults[name]).then((vectorInfo) => {
                                inputResults[name].info = vectorInfo;
                            });
                        }
                        inputResults[name].info = info;
                    } else E{
                        setLegacyType();
                    }
                    return true;
                }).catch(() => setLegacyType());
                promises.push(infoPromise);
            }
 
            clearOptions(optStr);
 
            Promise.allSettled(promises).then(() => {
                const datasets = Object.values(inputResults);
 
                // unmount();
 
                if (datasets.length > 0 || errors.length === 0) {
                    resolve({ datasets, errors });
                } else {
                    reject(errors);
                }
            });
        });
    });
}