UNPKG

mime-lib

Version:
281 lines (229 loc) 6.58 kB
var fs = require( 'fs' ); var path = require( 'path' ); var typesData = require( './mime.types.json' ); /** * MIME constructor */ function MIME() { var self = this; this.types = Object.create( null ); this.extensions = Object.create( null ); for ( var type in typesData ) { var exts = typesData[ type ]; self.extensions[ type ] = exts; exts.forEach( function( ext ) { self.types[ ext ] = type; }); } this.default = this.types[ 'bin' ]; } /** * Iconv constructor * @type {Iconv} */ MIME.Iconv = require( 'iconv-lite' ) /** * MIME prototype * @type {Object} */ MIME.prototype = { /** * Looks up MIME type by extension. * * @param {String} extension * @return {String} MIME type */ type: function( extension ) { return this.types[ extension ] || this.default }, /** * Looks up file extensions by MIME type. * * @param {String} type MIME type * @return {Array} File extensions */ extension: function( type ) { return this.extensions[ type ] }, /** * Base64 encodes a buffer or string. * * @param {String|Buffer} input * @param {String} charset * @return {String} */ encodeBase64: function( input, charset ) { if( charset && !Buffer.isBuffer( input ) ) { return MIME.Iconv.encode( input, charset ) } else { return Buffer.isBuffer( input ) ? input.toString( 'base64' ) : Buffer.from( input ).toString( 'base64' ) } }, /** * Decodes a base64 encoded string. * * @param {String} input * @param {String} charset * @return {String|Buffer} */ decodeBase64: function( input, charset ) { if( /iso-?2022-?jp/i.test( charset ) ) { charset = 'shift_jis' } if( charset ) { return MIME.Iconv.decode( Buffer.from( input, 'base64' ), charset ) } else { return Buffer.from( input, 'base64' ).toString() } }, /** * Encodes a string into Quoted-printable format. * * @param {String} input * @param {Boolean} wordMode * @return {String} */ encodeQP: function( input, wordMode ) { var bytes = !Buffer.isBuffer( input ) ? Buffer.from( input ) : input var chr, out = '', len = bytes.length for( var i = 0; i < len; i++ ) { chr = bytes[i] if( wordMode ) { // if matches /[\x3D]|[^\x09\x0D\x0A\x20-\x7E]/gm out = chr !== 0x3D && ( chr >= 0x20 && chr <= 0x007E ) || ( chr === 0x09 || chr === 0x0D || chr === 0x0A ) ? out + String.fromCharCode( chr ) : out + '=' + chr.toString( 16 ).toUpperCase() } else { // if matches /[\x3D\x5F\x3F]|[^\x21-\x7E]/gm out = (chr !== 0x3D && chr !== 0x5F && chr !== 0x3F) && (chr >= 0x21 && chr <= 0x007E) ? out + String.fromCharCode( chr ) : out + '=' + chr.toString( 16 ).toUpperCase() } } return out }, /** * Decodes a string from Quoted-printable format. * * @param {String} input * @param {Boolean} multibyte * @param {Boolean} wordMode * @return {String} */ decodeQP: function( input, charset, wordMode ) { if( !wordMode ) { input = input.replace( /[=]\r?\n/gm, '' ) input = input.replace( /[=]$/, '' ) } else { input = input.replace( /_/g, ' ' ) } var byteLength = Buffer.byteLength( input ) - (( input.match( /=[0-9A-F]{2}/gi ) || [] ).length * 2 ) var buffer = Buffer.alloc( byteLength ) var pos = 0 var hex = null charset = ( charset || 'utf8' ).toLowerCase() if( /iso-?2022-?jp/i.test( charset ) ) { charset = 'shift_jis' } for( var i = 0; i < input.length; i++ ) { if( input[i] === '=' ) { hex = input.substr( i + 1, 2 ) if( /[A-F0-9]{2}/i.test( hex ) ) { buffer[ pos++ ] = parseInt( hex, 16 ) i += 2 continue } } buffer[ pos++ ] = input.charCodeAt( i ) } return /^(ascii|utf-?8|utf-?16-?le|ucs-?2)$/i.test( charset ) ? buffer.toString( charset.replace( /-/g, '' ) ) : MIME.Iconv.decode( buffer, charset ) }, /** * Encodes a string into mime encoded word format. * <http://en.wikipedia.org/wiki/MIME#Encoded-Word> * * @param {String} input * @param {String} type * @param {String} charset * @return {String} */ encodeWord: function( input, type, charset ) { type = ( type || 'Q' ).toUpperCase() charset = ( charset || 'utf-8' ).toUpperCase() if( type === 'B' ) { input = this.encodeBase64( input, charset ) } input = this.encodeQP( input, true ) input = [ charset, type, input ].join( '?' ) return '=?' + input + '?=' }, /** * Decodes a string from mime encoded word format. * @see #encodeWord() * * @param {String} input * @return {String} */ decodeWord: function( input ) { var self = this return input.replace( /[=][?]([^?]+)[?]([a-z])[?]([^?]*)[?][=]/gi, function( match, charset, type, data ) { type = type.toUpperCase() return type === 'B' ? self.decodeBase64( data, charset ) : self.decodeQP( data, charset, true ) } ) }, /** * Folds a long line according to the RFC 5322. * <http://tools.ietf.org/html/rfc5322#section-2.1.1> * * @param {String} input * @param {Number} maxLength * @param {Boolean} hardWrap * @return {String} */ foldLine: require( 'foldline' ), /** * [urlEncode description] * @param {String} input * @return {String} */ urlEncode: function( input ) { var len = input.length var chr, out = '' function hex( number ) { return number.toString( 16 ).toUpperCase() } for( var i = 0; i < len; i++ ) { chr = input.charCodeAt( i ) if( chr >= 0x41 && chr <= 0x5A ) { out = out + input[i] } else if( chr >= 0x61 && chr <= 0x7A ) { out = out + input[i] } else if( chr >= 0x30 && chr <= 0x39 ) { out = out + input[i] } else if( input[i].match( /[-_.!~*'()]/ ) ) { out = out + input[i] } else if( chr <= 0x007F ) { out = out + '%' + hex( chr ) } else if( chr <= 0x07FF ) { out = out + '%' + hex( 0xC0 | (chr >> 6) ) out = out + '%' + hex( 0x80 | (chr & 0x3F) ) } else { out = out + '%' + hex( 0xE0 | (chr >> 12) ) out = out + '%' + hex( 0x80 | ((chr >> 6) & 0x3F) ) out = out + '%' + hex( 0x80 | (chr & 0x3F) ) } } return out } } module.exports = new MIME