import { fileTypeForExtension , FileType , fileTypeForMimeType , nameForFileType , extensionForFileType , isBinaryFileType , Directory } from "./models" ; export function toAddress ( n ) { let s = n . toString ( 16 ) ; while ( s . length < 6 ) { s = "0" + s ; } return "0x" + s ; } export function padRight ( s , n , c ) { s = String ( s ) ; while ( s . length < n ) { s = s + c ; } return s ; } export function padLeft ( s , n , c ) { s = String ( s ) ; while ( s . length < n ) { s = c + s ; } return s ; } const x86JumpInstructions = [ "jmp" , "ja" , "jae" , "jb" , "jbe" , "jc" , "je" , "jg" , "jge" , "jl" , "jle" , "jna" , "jnae" , "jnb" , "jnbe" , "jnc" , "jne" , "jng" , "jnge" , "jnl" , "jnle" , "jno" , "jnp" , "jns" , "jnz" , "jo" , "jp" , "jpe" , "jpo" , "js" , "jz" ] ; export function isBranch ( instr ) { return x86JumpInstructions . indexOf ( instr . mnemonic ) >= 0 ; } const base64DecodeMap = [ 62 , 0 , 0 , 0 , 63 , 52 , 53 , 54 , 55 , 56 , 57 , 58 , 59 , 60 , 61 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 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 , 0 , 0 , 0 , 0 , 0 , 0 , 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 ] ; const base64DecodeMapOffset = 0x2B ; const base64EOF = 0x3D ; const _concat3array = new Array ( 3 ) ; const _concat4array = new Array ( 4 ) ; const _concat9array = new Array ( 9 ) ; /**
 * The concatN() functions concatenate multiple strings in a way that
 * avoids creating intermediate strings, unlike String.prototype.concat().
 *
 * Note that these functions don't have identical behaviour to using '+',
 * because they will ignore any arguments that are |undefined| or |null|.
 * This usually doesn't matter.
 */ export function concat3 ( s0 , s1 , s2 ) { _concat3array [ 0 ] = s0 ; _concat3array [ 1 ] = s1 ; _concat3array [ 2 ] = s2 ; return _concat3array . join ( "" ) ; } export function concat4 ( s0 , s1 , s2 , s3 ) { _concat4array [ 0 ] = s0 ; _concat4array [ 1 ] = s1 ; _concat4array [ 2 ] = s2 ; _concat4array [ 3 ] = s3 ; return _concat4array . join ( "" ) ; } export function base64EncodeBytes ( bytes ) { let base64 = "" ; const encodings = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ; const byteLength = bytes . byteLength ; const byteRemainder = byteLength % 3 ; const mainLength = byteLength - byteRemainder ; let a ; let b ; let c ; let d ; let chunk ; for ( let i = 0 ; i < mainLength ; i = i + 3 ) { chunk = ( bytes [ i ] << 16 ) | ( bytes [ i + 1 ] << 8 ) | bytes [ i + 2 ] ; a = ( chunk & 16515072 ) >> 18 ; b = ( chunk & 258048 ) >> 12 ; c = ( chunk & 4032 ) >> 6 ; d = chunk & 63 ; base64 += concat4 ( encodings [ a ] , encodings [ b ] , encodings [ c ] , encodings [ d ] ) ; } if ( byteRemainder === 1 ) { chunk = bytes [ mainLength ] ; a = ( chunk & 252 ) >> 2 ; b = ( chunk & 3 ) << 4 ; base64 += concat3 ( encodings [ a ] , encodings [ b ] , "==" ) ; } else if ( byteRemainder === 2 ) { chunk = ( bytes [ mainLength ] << 8 ) | bytes [ mainLength + 1 ] ; a = ( chunk & 64512 ) >> 10 ; b = ( chunk & 1008 ) >> 4 ; c = ( chunk & 15 ) << 2 ; base64 += concat4 ( encodings [ a ] , encodings [ b ] , encodings [ c ] , "=" ) ; } return base64 ; } export function decodeRestrictedBase64ToBytes ( encoded ) { let ch ; let code ; let code2 ; const len = encoded . length ; const padding = encoded . charAt ( len - 2 ) === "=" ? 2 : encoded . charAt ( len - 1 ) === "=" ? 1 : 0 ; const decoded = new Uint8Array ( ( encoded . length >> 2 ) * 3 - padding ) ; for ( let i = 0 , j = 0 ; i < encoded . length ; ) { ch = encoded . charCodeAt ( i ++ ) ; code = base64DecodeMap [ ch - base64DecodeMapOffset ] ; ch = encoded . charCodeAt ( i ++ ) ; code2 = base64DecodeMap [ ch - base64DecodeMapOffset ] ; decoded [ j ++ ] = ( code << 2 ) | ( ( code2 & 0x30 ) >> 4 ) ; ch = encoded . charCodeAt ( i ++ ) ; if ( ch === base64EOF ) { return decoded ; } code = base64DecodeMap [ ch - base64DecodeMapOffset ] ; decoded [ j ++ ] = ( ( code2 & 0x0f ) << 4 ) | ( ( code & 0x3c ) >> 2 ) ; ch = encoded . charCodeAt ( i ++ ) ; if ( ch === base64EOF ) { return decoded ; } code2 = base64DecodeMap [ ch - base64DecodeMapOffset ] ; decoded [ j ++ ] = ( ( code & 0x03 ) << 6 ) | code2 ; } return decoded ; } const layoutThrottleDuration = 10 ; let layoutTimeout = 0 ; export function layout ( ) { if ( layoutTimeout ) { window . clearTimeout ( layoutTimeout ) ; } window . setTimeout ( ( ) => { layoutTimeout = 0 ; document . dispatchEvent ( new Event ( "layout" ) ) ; } , layoutThrottleDuration ) ; } export function resetDOMSelection ( ) { window . getSelection ( ) . removeAllRanges ( ) ; } export function assert ( c , message ? ) { if ( ! c ) { throw new Error ( message ) ; } } export function clamp ( x , min , max ) { return Math . min ( Math . max ( min , x ) , max ) ; } export async function readUploadedFile ( inputFile , readAs ) { const temporaryFileReader = new FileReader ( ) ; return new Promise < string | ArrayBuffer > ( ( resolve , reject ) => { temporaryFileReader . onerror = ( ) => { temporaryFileReader . abort ( ) ; reject ( new DOMException ( "Problem parsing input file." ) ) ; } ; temporaryFileReader . onload = ( ) => { resolve ( temporaryFileReader . result as any ) ; } ; if ( readAs === "text" ) { temporaryFileReader . readAsText ( inputFile ) ; } else if ( readAs === "arrayBuffer" ) { temporaryFileReader . readAsArrayBuffer ( inputFile ) ; } else { assert ( false , "NYI" ) ; } } ) ; } export async function readUploadedDirectory ( inputEntry , root , customRoot ? ) { const reader = inputEntry . createReader ( ) ; reader . readEntries ( ( ( entries ) => { entries . forEach ( async ( entry ) => { if ( entry . isDirectory ) { return readUploadedDirectory ( entry , root , customRoot ) ; } entry . file ( async ( file ) => { try { const name = file . name ; let path = entry . fullPath . replace ( /^\/+/g , "" ) ; if ( customRoot ) { const pathArray = path . split ( "/" ) ; pathArray [ 0 ] = customRoot ; path = pathArray . join ( "/" ) ; } const fileType = fileTypeForExtension ( name . split ( "." ) . pop ( ) ) ; const data = await readUploadedFile ( file , isBinaryFileType ( fileType ) ? "arrayBuffer" : "text" ) ; const newFile = root . newFile ( path , fileType , false , true ) ; newFile . setData ( data ) ; } catch ( e ) { console . log ( "Unable to read the file!" ) ; } } ) ; } ) ; } ) ) ; } export async function uploadFilesToDirectory ( items , root ) { Array . from ( items ) . forEach ( async ( item ) => { if ( typeof item . webkitGetAsEntry === "function" ) { const entry = item . webkitGetAsEntry ( ) ; if ( entry . isDirectory ) { if ( root . getImmediateChild ( entry . name ) ) { const customRoot = root . handleNameCollision ( entry . name ) ; return readUploadedDirectory ( entry , root , customRoot ) ; } return readUploadedDirectory ( entry , root ) ; } } let file ; if ( item instanceof DataTransferItem ) { file = item . getAsFile ( ) ; } else { file = item ; } const name = file . name ; const path = ( file as any ) . webkitRelativePath || name ; const fileType = fileTypeForExtension ( name . split ( "." ) . pop ( ) ) ; let data ; try { data = await readUploadedFile ( file , isBinaryFileType ( fileType ) ? "arrayBuffer" : "text" ) ; const newFile = root . newFile ( path , fileType , false , true ) ; newFile . setData ( data ) ; } catch ( e ) { console . log ( "Unable to read the file!" ) ; } } ) ; } export function isUploadAllowedForMimeType ( type ) { if ( type === "" ) { return true ; } return fileTypeForMimeType ( type ) !== FileType . Unknown ; } let nextKey = 0 ; export function getNextKey ( ) { return nextKey ++ ; } export function validateFileName ( name , sourceType ) { if ( ! name ) { return "File name can't be empty" ; } if ( ! /^[a-z0-9\.\-\_]+$/i . test ( name ) ) { return "Illegal characters in file name" ; } const sourceTypeExtension = "." + extensionForFileType ( sourceType ) ; if ( sourceTypeExtension === name ) { return "File name can't be empty" ; } if ( ! name . endsWith ( sourceTypeExtension ) ) { return `${ nameForFileType ( sourceType ) } file extension is missing or incorrect` ; } return "" ; }