**** A standard bean class representing a .FMP map. See `MapViewer` for details on rendering a ** `MappyMap` to the screen.** @Jsclass MapLoader {privateconststatic Log log := Log.get(MapLoader#.name)protected Str:Type chunkLoaders := [:]protected Int mapSize// ---- Constructors ------------------------------------------------------internalnew make(){// by having instances of MapLoaders they become self initialising and// the ChunkLoader instances (below) get automatically garbage collected registerChunkLoaders}// ---- Public Methods ----------------------------------------------------** Create a `MappyMap` from the given input stream of .FMP data.** ** Note this method closes the input stream.static MappyMap loadMap(InStream fmpStream){return MapLoader().doLoadMap(fmpStream)}// ---- Protected Methods -------------------------------------------------** Performs the actual FMP map loading. private MappyMap doLoadMap(InStream fmpStream){ log.debug("loadMap() - Starting...") log.info("Loading Map from InputStream")try{ map := MappyMap()// load the map header chkMapHeader := createChunkLoader(fmpStream, Endian.big)if(chkMapHeader.chunkName != "FORM")throw FantomMappyErr("Map does not start with chunk [FORM] :: ChunkIf = [$chkMapHeader.chunkName]")// find out how many bytes are contained in the map data chkMapHeader.loadChunk(map) bytesToRead := mapSize - 4// read chunks while there's still chunks to readwhile(bytesToRead > 0){// find and create the next chunk loader chunkLoader := createChunkLoader(fmpStream, map.mapHeader.endian)// load the chunk chunkLoader.loadChunk(map)// check that all the data was loadedif(chunkLoader.bytesRemaining > 0){ log.warn("Chunk [$chunkLoader.chunkName] still has [$chunkLoader.bytesRemaining] bytes remaining, skipping...");}// the countdown continues bytesToRead -= 8 // for the chunk header bytesToRead -= chunkLoader.chunkSize} log.debug("loadMap() - Done.")return map}finally{ fmpStream.close}}// ---- Internal Methods -------------------------------------------------** Factory method for producing instances of ChunkLoaders.** Note: This method does not close the given input stream.internal ChunkLoader createChunkLoader(InStream fmpStream, Endian endian){ log.debug("createChunkLoader() - Starting...") ChunkLoader? chunkLoader := null Str? errorMessage := nulltry{ errorMessage = "Could not read chunkId" chunkId := fmpStream.readChars(4) errorMessage = "Could not read chunk length for ChunkId [$chunkId]" chunkSize := fmpStream.readU4 // ignore the LSB / MSB thing for chunk lengthsif(chunkId == "FORM")// a little fudge mapSize = chunkSize errorMessage = "Could not read raw chunk data for ChunkId [$chunkId]" buf := fmpStream.readBufFully(null, chunkId == "FORM" ? 4 : chunkSize)// set a default return value errorMessage = "Problem creating DefaultChunkLoader" chunkLoader = DefaultChunkLoader(chunkId, buf, endian)// find actual ChunkLoader errorMessage = "Could not find ChunkLoader for ChunkId [$chunkId]" chunkLoaderType := chunkLoaders.getOrThrow(chunkId) errorMessage = "Problem initialising ChunkLoader for ChunkId [$chunkId]" chunkLoader = chunkLoaderType.make([chunkId, buf, endian])}catch(Err e){// always return a default chunk loader if we can, so we may// continue reading the rest of the map. Not finding a particular// ChunkLoader is going to be a common problem.if(chunkLoader != null){ log.warn(errorMessage)}else{ log.warn("Sya yo!!! $e.msg")throw ChunkLoadErr(errorMessage, e)}} log.info(chunkLoader.toStr) log.debug("createChunkLoader() - Done.")return chunkLoader}** This is where we hard code chunk loader class references to chunk names.** We do this so that (J2ME) obfuscaters can rename classes. It also allows** us to delete empty chunk loader classes like ChunkLoaderLRYx. internal Void registerChunkLoaders(){ chunkLoaders["ANDT"] = ChunkLoaderANDT# chunkLoaders["ATHR"] = ChunkLoaderATHR#// chunkLoaders["BGFX"] = ChunkLoaderBGFX# chunkLoaders["BKDT"] = ChunkLoaderBKDT#// chunkLoaders["CMAP"] = ChunkLoaderCMAP# chunkLoaders["FORM"] = ChunkLoaderFORM# chunkLoaders["MPHD"] = ChunkLoaderMPHD#// chunkLoaders["OBDT"] = ChunkLoaderOBDT#// chunkLoaders["OBFN"] = ChunkLoaderOBFN#// chunkLoaders["TSTR"] = ChunkLoaderTSTR# chunkLoaders["BODY"] = ChunkLoaderBODY# chunkLoaders["LYR1"] = ChunkLoaderBODY# chunkLoaders["LYR2"] = ChunkLoaderBODY# chunkLoaders["LYR3"] = ChunkLoaderBODY# chunkLoaders["LYR4"] = ChunkLoaderBODY# chunkLoaders["LYR5"] = ChunkLoaderBODY# chunkLoaders["LYR6"] = ChunkLoaderBODY# chunkLoaders["LYR7"] = ChunkLoaderBODY#}}@Jsinternalclass DefaultChunkLoader : ChunkLoader {new make(Str chunkName, Buf chunkData, Endian endian) : super(chunkName, chunkData, endian){}override Void loadChunk(MappyMap map){// prevent the warning logsuper.skip(super.bytesRemaining)}}