/* DemoFormatInputStream.java (c) 2012-2014 Edward Swartz All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html */ package v9t9.engine.demos.format; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Queue; import java.util.Set; import v9t9.common.demos.DemoHeader; import v9t9.common.demos.IDemoEvent; import v9t9.common.demos.IDemoEventFormatter; import v9t9.common.demos.IDemoFormatterRegistry; import v9t9.common.demos.IDemoInputEventBuffer; import v9t9.common.demos.IDemoInputStream; import v9t9.common.events.NotifyException; import v9t9.common.machine.IMachineModel; import v9t9.engine.demos.events.TimerTick; import v9t9.engine.demos.stream.BaseDemoInputStream; /** * Reader for new format, using variable-length registers and values. * @author ejs * */ public class DemoFormatInputStream extends BaseDemoInputStream implements IDemoInputStream { private int ticks; private DemoHeader header; private Map<Integer, IDemoInputEventBuffer> buffers = new HashMap<Integer, IDemoInputEventBuffer>(); private Set<Integer> unknownBuffers = new HashSet<Integer>(); public DemoFormatInputStream(IMachineModel machineModel, byte[] magic, InputStream is_) throws IOException, NotifyException { super(is_); header = new DemoHeader(magic); header.read(is); if (!machineModel.isModelCompatible(header.getMachineModel())) { throw new NotifyException(null, "Note: this demo is incompatible with the "+ "current machine: " + header.getMachineModel() + " expected"); } for (Map.Entry<Integer, String> ent : header.getBufferIdentifierMap().entrySet()) { final IDemoEventFormatter formatter = IDemoFormatterRegistry.INSTANCE.findFormatterByBuffer( ent.getValue()); DemoInputEventBuffer buffer; if (formatter != null) { buffer = new DemoFormatterInputEventBuffer(is, ent.getKey(), ent.getValue(), formatter); } else { // callers should invoke #registerBuffer later -- or not at all buffer = new DemoInputEventBuffer(is, ent.getKey(), ent.getValue()) { @Override public void decodeEvents(Queue<IDemoEvent> queuedEvents) throws IOException { if (!unknownBuffers.contains(getCode())) { System.err.println("0x" + Long.toHexString(getPosition()) + ": unrecognized code " + getCode() + " encountered"); unknownBuffers.add(getCode()); } readRest(); } }; } registerBuffer(buffer); } } public void registerBuffer(IDemoInputEventBuffer buffer) { buffers.put(buffer.getCode(), buffer); } /* (non-Javadoc) * @see v9t9.common.demo.IDemoInputStream#getTimerRate() */ @Override public int getTimerRate() { return header.getTimerRate(); } /* (non-Javadoc) * @see v9t9.common.demo.IDemoInputStream#getElapsedTime() */ @Override public long getElapsedTime() { return ticks * 1000L / getTimerRate(); } /* (non-Javadoc) * @see v9t9.engine.demos.stream.BaseDemoInputStream#ensureEvents() */ @Override protected void ensureEvents() throws IOException { while (queuedEvents.isEmpty()) { int code = is.read(); if (code < 0) { return; } if (code == 0) { //System.out.println(Long.toHexString(is.getPosition()) + ": tick" ); queueTimerTickEvent(); continue; } IDemoInputEventBuffer buffer = buffers.get(code); if (buffer == null) { throw new IOException("unknown buffer for " + code); } //System.out.println(Long.toHexString(is.getPosition()) + ": " + // buffer.getIdentifier()); // get contents buffer.refill(); // decode em buffer.decodeEvents(queuedEvents); } } protected void queueTimerTickEvent() throws IOException { int count = getInputStream().read(); while (count-- > 0) { ticks++; queuedEvents.add(new TimerTick(getElapsedTime())); } } }