private void readBlocks(RandomAccessFile data) throws IOException {
		boolean readNext = true;
		while (readNext) {
			int mapX = data.readUnsignedShort();
			int mapY = data.readUnsignedShort();
			short musicIndex = data.readShort();
			short ambienceIndex = data.readShort();

			short mapIconIndex = data.readShort();
			short doorBytes = data.readShort();
			byte scrollByte = data.readByte();

			// read map color
			int mapColorRed = data.readUnsignedByte();
			int mapColorGreen = data.readUnsignedByte();
			int mapColorBlue = data.readUnsignedByte();
			Color mapColor = new Color(mapColorRed, mapColorGreen, mapColorBlue, MAP_COLOR_ALPHA);

			short mapMarkingBytes = data.readShort();
			Block newBlock = new Block(this.blockSizeX, this.blockSizeY, musicIndex,
					ambienceIndex, mapIconIndex, doorBytes, scrollByte, mapColor,
					mapMarkingBytes);
			this.addBlock(newBlock, mapX, mapY);

			boolean readLayers = true;
			while (readLayers) {
				// read layer data
				byte layerID = data.readByte();
				switch (LayerID.getLayerID(layerID & 0xFF)) {
				case TILE_COLLISION:
					data.readByte(); // advance past fake index FF present for alignment
					newBlock.setCollisionLayer(new CollisionLayer(newBlock, data, this));
					break;
				case COLOR_DECORATION:
					newBlock.addLayer(new ColorLayer(newBlock, data));
					break;
				case TILE_DECORATION:
				case IMAGE_DECORATION:
				case ENTITY_DATA:
					ZettaUtil.error("Layer type %s not implemented yet",
							LayerID.getLayerID(layerID).name());
					break;
				case END_OF_FILE:
					data.readByte();
					return;
				case END_BLOCK:
					readLayers = false;
					data.readByte(); // advance
					break;
				default: ZettaUtil.error("Unknown layer ID %d", layerID); break;
				}
			}
		}
	}