简体   繁体   中英

How can we validate SVG Image without using magic number in AngularJS

We are currently validating images using magic number. Since SVG doesn't support magic number, what is the good way to validate SVG files in angularJS?

This is how we are validating other images -

angular.module('fileMimeTypeServiceModule', [])
.constant('fileMimeTypeServiceConstants', {
    VALID_IMAGE_MIME_TYPE_CODES: ['FFD8FFDB', 'FFD8FFE0', 'FFD8FFE1', '474946383761', '424D', '49492A00', '4D4D002A', '89504E470D0A1A0A']
})
.factory('seFileReader', function() {
    var read = function(file, config) {
        var fileReader = new FileReader();

        config = config || {};
        fileReader.onloadend = config.onLoadEnd;
        fileReader.onerror = config.onError;

        fileReader.readAsArrayBuffer(file);
        return fileReader;
    };

    return {
        read: read
    };
})
.factory('fileMimeTypeService', function(fileMimeTypeServiceConstants, seFileReader, $q) {
    var _validateMimeTypeFromFile = function(loadedFile) {
        var fileAsBytes = (new Uint8Array(loadedFile)).subarray(0, 8);
        var header = fileAsBytes.reduce(function(header, byte) {
            var byteAsStr = byte.toString(16);
            if (byteAsStr.length === 1) {
                byteAsStr = '0' + byteAsStr;
            }
            header += byteAsStr;
            return header;
        }, '');

        return fileMimeTypeServiceConstants.VALID_IMAGE_MIME_TYPE_CODES.some(function(mimeTypeCode) {
            return header.toLowerCase().indexOf(mimeTypeCode.toLowerCase()) === 0; // validating here
        });
    };

    var isFileMimeTypeValid = function(file) {
        var deferred = $q.defer();
        seFileReader.read(file, {
            onLoadEnd: function(e) {
                if (_validateMimeTypeFromFile(e.target.result)) {
                    deferred.resolve();
                } else {
                    deferred.reject();
                }
            },
            onError: function() {
                deferred.reject();
            }
        });
        return deferred.promise;
    };

    return {
        isFileMimeTypeValid: isFileMimeTypeValid
    };
});

Now i want to validate SVG images as well, how can we validate it without magic number?

SVG images are XML files. In a first step, you can test for the XML magic number. Afterwards, you could read the file content as text and parse it with DOMParser . If an error occurs, this will tell you the file was invalid.

This example uses the TextDecoder API to convert the array buffer to string. This might be a bit more restricting than doing it with a separate async FileReader.readAsText() operation. You should review browser compatibility to find out if this solution is good enough.

angular.module('fileMimeTypeServiceModule', [])
.constant('fileMimeTypeServiceConstants', {
    VALID_IMAGE_MIME_TYPE_CODES: [ 'ffd8ffdb', 'ffd8ffe0', 'ffd8ffe1', '474946383761', '424d', '49492a00', '4d4d002a', '89504e470d0a1a0a' ],
    XML_MIME_TYPE_CODE: '3c3f786d6c'
})
.factory('seFileReader', function() {/*...*/})
.factory('fileMimeTypeService', function(fileMimeTypeServiceConstants, seFileReader, $q) {
    var _validateMimeTypeFromFile = function(loadedFile) {
        var u8arr = new Uint8Array(loadedFile);
        var fileAsBytes = (u8arr).subarray(0, 8);
        var header = fileAsBytes.reduce(function(header, byte) {
            var byteAsStr = byte.toString(16);
            if (byteAsStr.length === 1) {
                byteAsStr = '0' + byteAsStr;
            }
            header += byteAsStr;
            return header;
        }, '');

        if (header.toLowerCase().startsWith(fileMimeTypeServiceConstants.XML_MIME_TYPE_CODE) {
            try {
                var fileContentAsString = new TextDecoder('utf-8').decode(u8arr);
                var parser = new DOMParser();
                parser.parseFromString(fileContentAsString, 'image/svg+xml');
                return true;
            } catch (e) {
                return false;
            }
        } else {
          return fileMimeTypeServiceConstants.VALID_IMAGE_MIME_TYPE_CODES.some(function(mimeTypeCode) {
              return header.toLowerCase().startsWith(mimeTypeCode); 
          });
        }
    };

    //...
});

Obviously, this could be a memory-consuming operation if you expect to test very large files, as the complete DOM for the SVG is constructed (but not rendered). My expectation would be that it is still the fastest and most reliable solution for all but some outlier use cases, like testing a large number of files in parallel.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM