@@ -154,6 +154,12 @@ namespace pxt {
154154 const existing = this . lookupByID ( id ) ;
155155
156156 if ( ! assetEquals ( existing , newValue ) ) {
157+ if ( ! validateAsset ( newValue ) && validateAsset ( existing ) ) {
158+ pxt . warn ( "Refusing to overwrite asset with invalid version" ) ;
159+ pxt . tickEvent ( "assets.invalidAssetOverwrite" , { assetType : newValue . type } ) ;
160+ return existing ;
161+ }
162+
157163 this . removeByID ( id ) ;
158164 asset = this . add ( newValue ) ;
159165 this . notifyListener ( newValue . internalID ) ;
@@ -1940,6 +1946,69 @@ namespace pxt {
19401946 return getShortIDCore ( asset . type , asset . id ) ;
19411947 }
19421948
1949+ export function validateAsset ( asset : pxt . Asset ) {
1950+ if ( ! asset ) return false ;
1951+
1952+ switch ( asset . type ) {
1953+ case AssetType . Image :
1954+ case AssetType . Tile :
1955+ return validateImageAsset ( asset as ProjectImage | Tile ) ;
1956+ case AssetType . Tilemap :
1957+ return validateTilemap ( asset as ProjectTilemap ) ;
1958+ case AssetType . Animation :
1959+ return validateAnimation ( asset as Animation )
1960+ case AssetType . Song :
1961+ return validateSong ( asset as Song ) ;
1962+ }
1963+ }
1964+
1965+ function validateImageAsset ( asset : ProjectImage | Tile ) {
1966+ if ( ! asset . bitmap ) return false ;
1967+
1968+ return validateBitmap ( sprite . Bitmap . fromData ( asset . bitmap ) ) ;
1969+ }
1970+
1971+ function validateTilemap ( tilemap : ProjectTilemap ) {
1972+ if (
1973+ ! tilemap . data ||
1974+ ! tilemap . data . tilemap ||
1975+ ! tilemap . data . tileset ||
1976+ ! tilemap . data . tileset . tileWidth ||
1977+ ! tilemap . data . tileset . tiles ?. length ||
1978+ ! tilemap . data . layers
1979+ ) {
1980+ return false ;
1981+ }
1982+
1983+ return validateBitmap ( sprite . Bitmap . fromData ( tilemap . data . layers ) ) &&
1984+ validateBitmap ( tilemap . data . tilemap ) ;
1985+ }
1986+
1987+ function validateAnimation ( animation : Animation ) {
1988+ if ( ! animation . frames ?. length || animation . interval <= 0 ) {
1989+ return false ;
1990+ }
1991+
1992+ return ! animation . frames . some ( frame => ! validateBitmap ( sprite . Bitmap . fromData ( frame ) ) ) ;
1993+ }
1994+
1995+ function validateBitmap ( bitmap : sprite . Bitmap ) {
1996+ return bitmap . width > 0 &&
1997+ bitmap . height > 0 &&
1998+ ! Number . isNaN ( bitmap . x0 ) &&
1999+ ! Number . isNaN ( bitmap . y0 ) &&
2000+ bitmap . data ( ) . data . length === bitmap . dataLength ( ) ;
2001+ }
2002+
2003+ function validateSong ( song : Song ) {
2004+ return song . song &&
2005+ song . song . ticksPerBeat > 0 &&
2006+ song . song . beatsPerMeasure > 0 &&
2007+ song . song . measures > 0 &&
2008+ song . song . beatsPerMinute > 0 &&
2009+ ! ! song . song . tracks ;
2010+ }
2011+
19432012 function getShortIDCore ( assetType : pxt . AssetType , id : string , allowNoPrefix = false ) {
19442013 let prefix : string ;
19452014 switch ( assetType ) {
@@ -2054,12 +2123,6 @@ namespace pxt {
20542123 }
20552124 }
20562125
2057-
2058- function set16Bit ( buf : Uint8ClampedArray , offset : number , value : number ) {
2059- buf [ offset ] = value & 0xff ;
2060- buf [ offset + 1 ] = ( value >> 8 ) & 0xff ;
2061- }
2062-
20632126 function read16Bit ( buf : Uint8ClampedArray , offset : number ) {
20642127 return buf [ offset ] | ( buf [ offset + 1 ] << 8 )
20652128 }
0 commit comments