Example #1
0
        protected override void LoadIndex(GameInfo game)
        {
            const byte encByte = 0x69;
            Directory = ServiceLocator.FileStorage.GetDirectoryName(game.Path);
            using (var file = ServiceLocator.FileStorage.OpenFileRead(game.Path))
            {
                var br = new BinaryReader(new XorStream(file,encByte));
                while (br.BaseStream.Position < br.BaseStream.Length)
                {
                    var block = ToTag(br.ReadBytes(4));
                    br.ReadUInt32BigEndian(); // size
                    switch (block)
                    {
                        case "RNAM":
                            ReadRoomNames(br);
                            break;

                        case "MAXS":
                            ReadMaxSizes(br);
                            break;

                        case "DROO":
                            var rooms = ReadResTypeList(br);
                            RoomResources = new ReadOnlyCollection<Resource>(rooms);
                            break;

                        case "DSCR":
                            var scripts = ReadResTypeList(br);
                            ScriptResources = new ReadOnlyCollection<Resource>(scripts);
                            break;

                        case "DSOU":
                            var sounds = ReadResTypeList(br);
                            SoundResources = new ReadOnlyCollection<Resource>(sounds);
                            break;

                        case "DCOS":
                            var costumes = ReadResTypeList(br);
                            CostumeResources = new ReadOnlyCollection<Resource>(costumes);
                            break;

                        case "DCHR":
                            var charset = ReadResTypeList(br);
                            CharsetResources = new ReadOnlyCollection<Resource>(charset);
                            break;

                        case "DOBJ":
                            ReadDirectoryOfObjects(br);
                            break;
                        default:
//                            Console.Error.WriteLine("Unknown block {0}", block);
                            break;
                    }
                }
            }
        }
Example #2
0
		internal UImage(string fileName)
		{
			using(var reader = new BinaryReader(File.OpenRead(fileName)))
			{
				reader.ReadBytes(8); // magic and CRC, already checked
				Timestamp = (new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc) + TimeSpan.FromSeconds(reader.ReadInt32BigEndian())).ToLocalTime();
				Size = reader.ReadUInt32BigEndian();
				LoadAddress = reader.ReadUInt32BigEndian();
				EntryPoint = reader.ReadUInt32BigEndian();
				CRC = reader.ReadUInt32BigEndian();
				OperatingSystem = (OS)reader.ReadByte();
				Architecture = (Architecture)reader.ReadByte();
				Type = (ImageType)reader.ReadByte();
				Compression = (CompressionType)reader.ReadByte();
				var nameAsBytes = reader.ReadBytes(32);
				Name = Encoding.UTF8.GetString(nameAsBytes.Reverse().SkipWhile(x => x == 0).Reverse().ToArray());
				image = reader.ReadBytes((int)Size);
			}
		}
Example #3
0
		public static UImageResult TryLoad(string fileName, out UImage uImage)
		{
			uImage = null;
			if(new FileInfo(fileName).Length < 64)
			{
				return UImageResult.NotUImage;
			}
			byte[] headerForCrc;
			using(var reader = new BinaryReader(File.OpenRead(fileName)))
			{
				headerForCrc = reader.ReadBytes(64);
				// we need to zero crc part
				for(var i = 4; i < 8; i++)
				{
					headerForCrc[i] = 0;
				}
			}
			using(var reader = new BinaryReader(File.OpenRead(fileName)))
			{
				var magic = reader.ReadUInt32BigEndian();
				if(magic != Magic)
				{
					return UImageResult.NotUImage;
				}
				var crc = reader.ReadUInt32BigEndian();
				if(crc != GzipCrc32(headerForCrc))
				{
					return UImageResult.BadChecksum;
				}
				reader.ReadBytes(22);
				var imageType = (ImageType)reader.ReadByte();
				if(!Enum.IsDefined(typeof(ImageType), imageType))
				{
					return UImageResult.NotSupportedImageType;
				}
				// TODO: check CRC of the header
				uImage = new UImage(fileName);
				return UImageResult.OK;
			}
		}
Example #4
0
        public override bool AppendData(BinaryReader b, int size)
        {
            if (_dataSize == -1)
            {
                Debug.Assert(size > 8);
                var imus_type = System.Text.Encoding.UTF8.GetString(b.ReadBytes(4));
                /*uint32 imus_size =*/
                b.ReadUInt32BigEndian();
//                if (imus_type != "iMUS")
//                    Console.Error.WriteLine("Invalid Chunk for imuse_channel");
                size -= 8;
                _tbufferSize = size;
                Debug.Assert(_tbufferSize != 0);
                _tbuffer = b.ReadBytes(size);
                _dataSize = -2;
            }
            else
            {
                if (_tbuffer.Length != 0)
                {
                    var old = _tbuffer;
                    int new_size = size + _tbufferSize;
                    _tbuffer = new byte[new_size];
                    Array.Copy(old, _tbuffer, _tbufferSize);
                    b.BaseStream.Read(_tbuffer, _tbufferSize, size);
                    _tbufferSize += size;
                }
                else
                {
                    _tbufferSize = size;
                    _tbuffer = new byte[_tbufferSize];
                    b.BaseStream.Read(_tbuffer, 0, size);
                }
            }

            ProcessBuffer();

            _srbufferSize = _sbufferSize;
            if (_sbuffer.Length != 0 && _bitsize == 12)
                Decode();

            return true;
        }
Example #5
0
        public override bool AppendData(BinaryReader b, int size)
        {
            if (_dataSize == -1)
            {
                Debug.Assert(size > 8);
                var saud_type = System.Text.Encoding.UTF8.GetString(b.ReadBytes(4));
                /*uint32 saud_size =*/
                b.ReadUInt32BigEndian();
                if (saud_type != "SAUD")
                    throw new NotSupportedException(string.Format("Invalid Chunk for SaudChannel : {0}", saud_type));
                size -= 8;
                _dataSize = -2;
            }
            if (_tbuffer.Length != 0)
            {
                var old = _tbuffer;
                _tbuffer = new byte[_tbufferSize + size];
                Array.Copy(old, _tbuffer, _tbufferSize);
                old = null;
                Array.Copy(b.ReadBytes(size), 0, _tbuffer, _tbufferSize, size);

                _tbufferSize += size;
            }
            else
            {
                _tbufferSize = size;
                _tbuffer = b.ReadBytes(_tbufferSize);
            }

            if (_keepSize)
            {
                _sbufferSize = _tbufferSize;
                _sbuffer = _tbuffer;
                _tbufferSize = 0;
                _tbuffer = new byte[0];
            }
            else
            {
                ProcessBuffer();
            }

            return true;
        }
Example #6
0
        void ReadMap()
        {
            var br = new BinaryReader(_stream);
            _stream.Seek(_mapOffset + 22, SeekOrigin.Begin);

            _resMap.resAttr = br.ReadUInt16BigEndian();
            _resMap.typeOffset = br.ReadUInt16BigEndian();
            _resMap.nameOffset = br.ReadUInt16BigEndian();
            _resMap.numTypes = br.ReadUInt16BigEndian();
            _resMap.numTypes++;

            _stream.Seek(_mapOffset + _resMap.typeOffset + 2, SeekOrigin.Begin);
            _resTypes = new ResType[_resMap.numTypes];

            for (int i = 0; i < _resMap.numTypes; i++)
            {
                _resTypes[i].id = br.ReadUInt32BigEndian();
                _resTypes[i].items = br.ReadUInt16BigEndian();
                _resTypes[i].offset = br.ReadUInt16BigEndian();
                _resTypes[i].items++;

                Debug.WriteLine("resType: <{0}> items: {1} offset: {2} (0x{3:X2})", _resTypes[i].id, _resTypes[i].items, _resTypes[i].offset, _resTypes[i].offset);
            }

            _resLists = new Resource[_resMap.numTypes][];

            for (int i = 0; i < _resMap.numTypes; i++)
            {
                _resLists[i] = new Resource[_resTypes[i].items];
                _stream.Seek(_resTypes[i].offset + _mapOffset + _resMap.typeOffset, SeekOrigin.Begin);

                for (int j = 0; j < _resTypes[i].items; j++)
                {
                    var resPtr = _resLists[i][j] = new Resource();

                    resPtr.id = br.ReadUInt16BigEndian();
                    resPtr.nameOffset = (short)br.ReadUInt16BigEndian();
                    resPtr.dataOffset = br.ReadUInt32BigEndian();
                    br.ReadUInt32BigEndian();

                    resPtr.attr = (byte)(resPtr.dataOffset >> 24);
                    resPtr.dataOffset &= 0xFFFFFF;
                }

                for (int j = 0; j < _resTypes[i].items; j++)
                {
                    if (_resLists[i][j].nameOffset != -1)
                    {
                        _stream.Seek(_resLists[i][j].nameOffset + _mapOffset + _resMap.nameOffset, SeekOrigin.Begin);

                        byte len = br.ReadByte();
						_resLists[i][j].name = br.ReadBytes(len).GetText();
                    }
                }
            }
        }
Example #7
0
            public bool LoadInstrument(Stream stream)
            {
                var br = new BinaryReader(stream);
                ushort soundType = br.ReadUInt16BigEndian();
                if (soundType != 1)
                {
                    Debug.WriteLine("Player_Mac::loadInstrument: Unsupported sound type {0}", soundType);
                    return false;
                }
                var typeCount = br.ReadUInt16BigEndian();
                if (typeCount != 1)
                {
                    Debug.WriteLine("Player_Mac::loadInstrument: Unsupported data type count %d", typeCount);
                    return false;
                }
                var dataType = br.ReadUInt16BigEndian();
                if (dataType != 5)
                {
                    Debug.WriteLine("Player_Mac::loadInstrument: Unsupported data type %d", dataType);
                    return false;
                }

                br.ReadUInt32BigEndian(); // initialization option

                var cmdCount = br.ReadUInt16BigEndian();
                if (cmdCount != 1)
                {
                    Debug.WriteLine("Player_Mac::loadInstrument: Unsupported command count %d", cmdCount);
                    return false;
                }
                var command = br.ReadUInt16BigEndian();
                if (command != 0x8050 && command != 0x8051)
                {
                    Debug.WriteLine("Player_Mac::loadInstrument: Unsupported command 0x%04X", command);
                    return false;
                }

                br.ReadUInt16BigEndian(); // 0
                var soundHeaderOffset = br.ReadUInt32BigEndian();

                stream.Seek(soundHeaderOffset, SeekOrigin.Begin);

                var soundDataOffset = br.ReadUInt32BigEndian();
                var size = br.ReadUInt32BigEndian();
                var rate = br.ReadUInt32BigEndian() >> 16;
                var loopStart = br.ReadUInt32BigEndian();
                var loopEnd = br.ReadUInt32BigEndian();
                byte encoding = br.ReadByte();
                byte baseFreq = br.ReadByte();

                if (encoding != 0)
                {
                    Debug.WriteLine("Player_Mac::loadInstrument: Unsupported encoding %d", encoding);
                    return false;
                }

                stream.Seek(soundDataOffset, SeekOrigin.Current);

                var data = br.ReadBytes((int)size);
                _instrument._data = data;
                _instrument._size = size;
                _instrument._rate = rate;
                _instrument._loopStart = loopStart;
                _instrument._loopEnd = loopEnd;
                _instrument._baseFreq = baseFreq;

                return true;
            }
Example #8
0
        /**
     * Read resource from the MacBinary file
     * @param typeID FourCC of the type
     * @param resID Resource ID to fetch
     * @return Pointer to a SeekableReadStream with loaded resource
     */
        public Stream GetResource(uint typeID, ushort resID)
        {
            var br = new BinaryReader(_stream);
            int typeNum = -1;
            int resNum = -1;

            for (int i = 0; i < _resMap.numTypes; i++)
                if (_resTypes[i].id == typeID)
                {
                    typeNum = i;
                    break;
                }

            if (typeNum == -1)
                return null;

            for (int i = 0; i < _resTypes[typeNum].items; i++)
                if (_resLists[typeNum][i].id == resID)
                {
                    resNum = i;
                    break;
                }

            if (resNum == -1)
                return null;

            _stream.Seek(_dataOffset + _resLists[typeNum][resNum].dataOffset, SeekOrigin.Begin);
            var len = (int)br.ReadUInt32BigEndian();

            // Ignore resources with 0 length
            if (len == 0)
                return null;

            return new MemoryStream(br.ReadBytes(len));
        }
Example #9
0
        bool Load(Stream stream)
        {
            var br = new BinaryReader(stream);
            if (_mode == Mode.None)
                return false;

            stream.Seek(_resForkOffset, SeekOrigin.Begin);

            _dataOffset = (uint)(br.ReadUInt32BigEndian() + _resForkOffset);
            _mapOffset = (uint)(br.ReadUInt32BigEndian() + _resForkOffset);
            _dataLength = br.ReadUInt32BigEndian();
            _mapLength = br.ReadUInt32BigEndian();

            // do sanity check
            if (stream.Position == stream.Length || _dataOffset >= stream.Length || _mapOffset >= stream.Length ||
                _dataLength + _mapLength > stream.Length)
            {
                _resForkOffset = -1;
                _mode = Mode.None;
                return false;
            }

            Debug.WriteLine("got header: data {0} [{1}] map {2} [{3}]",
                _dataOffset, _dataLength, _mapOffset, _mapLength);

            _stream = stream;

            ReadMap();
            return true;
        }
Example #10
0
        public override void LoadMusic(byte[] data)
        {
            input = new MemoryStream(data);
            UnloadMusic();

            int midiType;
            var isGmf = false;
            var br = new BinaryReader(input);
            var sig = br.ReadBytes(4);
            input.Seek(0, SeekOrigin.Begin);

            if (AreEquals(sig, "RIFF"))
            {
                // Skip the outer RIFF header.
                input.Seek(8, SeekOrigin.Current);
            }

            if (AreEquals(sig, "MThd"))
            {
                // SMF with MTHd information.
                input.Seek(4, SeekOrigin.Current);
                var len = br.ReadUInt32BigEndian();
                if (len != 6)
                {
                    throw new InvalidOperationException(string.Format("MThd length 6 expected but found {0}", len));
                }
                br.ReadByte(); //?
                midiType = br.ReadByte();
                // Verify that this MIDI either is a Type 2
                // or has only 1 track. We do not support
                // multitrack Type 1 files.
                NumTracks = br.ReadUInt16BigEndian();
                
                if (midiType > 2 /*|| (midiType < 2 && _numTracks > 1)*/)
                {
                    throw new InvalidOperationException(string.Format("No support for a Type {0} MIDI with {1} tracks", midiType, NumTracks));
                }
                PulsesPerQuarterNote = br.ReadUInt16BigEndian();
            }
            else if (AreEquals(sig, "GMF\x1"))
            {
                // Older GMD/MUS file with no header info.
                // Assume 1 track, 192 PPQN, and no MTrk headers.
                isGmf = true;
                midiType = 0;
                NumTracks = 1;
                PulsesPerQuarterNote = 192;
                // 'GMD\x1' + 3 bytes of useless (translate: unknown) information
                input.Seek(7, SeekOrigin.Current);
            }
            else
            {
                throw new InvalidOperationException(string.Format("Expected MThd or GMD header but found '{0}{1}{2}{3}' instead", sig[0], sig[1], sig[2], sig[3]));
            }

            // Now we identify and store the location for each track.
            if (NumTracks > Tracks.Length)
            {
                throw new InvalidOperationException(string.Format("Can only handle {0} tracks but was handed {1}", Tracks.Length, NumTracks));
            }

            uint totalSize = 0;
            var tracksRead = 0;
            while (tracksRead < NumTracks)
            {
                sig = br.ReadBytes(4);
                if (!AreEquals(sig, "MTrk") && !isGmf)
                {
                    var msg = new StringBuilder();
                    msg.AppendFormat("Position: {0} ('{1}')", input.Position - 4, (char)sig[0]).AppendLine();
                    msg.AppendFormat("Hit invalid block '{0}{1}{2}{3}' while scanning for track locations", sig[0], sig[1], sig[2], sig[3]);
                    throw new InvalidOperationException(msg.ToString());
                }

                // If needed, skip the MTrk and length bytes
                Tracks[tracksRead] = new Track{ Position = input.Position + (isGmf ? -4 : 4) };
                if (!isGmf)
                {
                    var len = br.ReadUInt32BigEndian();
                    totalSize += len;
                    input.Seek(len, SeekOrigin.Current);
                }
                else
                {
                    // TODO: vs An SMF End of Track meta event must be placed
                    // at the end of the stream.
//                    data[size++] = 0xFF;
//                    data[size++] = 0x2F;
//                    data[size++] = 0x00;
//                    data[size++] = 0x00;
                    throw new NotImplementedException("Gmf not implemented");
                }
                ++tracksRead;
            }

            // If this is a Type 1 MIDI, we need to now compress
            // our tracks down into a single Type 0 track.
            //_buffer = 0;

            if (midiType == 1)
            {
                // FIXME: Doubled the buffer size to prevent crashes with the
                // Inherit the Earth MIDIs. Jamieson630 said something about a
                // better fix, but this will have to do in the meantime.
//                _buffer = (byte*)malloc(size * 2);
//                compressToType0();
//                _numTracks = 1;
//                _tracks[0] = _buffer;
                throw new NotImplementedException("MidiType 1 not yet implemented.");
            }

            // Note that we assume the original data passed in
            // will persist beyond this call, i.e. we do NOT
            // copy the data to our own buffer. Take warning....
            ResetTracking();
            Tempo = 500000;
            ActiveTrack = 0;
        }
Example #11
0
        internal protected byte[] FindStartOfSound(int sound, ChunkType ct = ChunkType.MThd | ChunkType.FORM)
        {
            int size, pos;

            var ptr = ScummEngine.Instance.ResourceManager.GetSound(ScummEngine.Instance.Sound.MusicType, sound);

            if (ptr == null)
            {
                Debug.WriteLine("IMuseInternal::findStartOfSound(): Sound {0} doesn't exist", sound);
                return null;
            }

            // Check for old-style headers first, like 'RO'
            const ChunkType trFlag = ChunkType.MThd | ChunkType.FORM;
            if (System.Text.Encoding.UTF8.GetString(ptr, 0, 3) == "ROL")
                return ct == trFlag ? ptr : null;
            if (System.Text.Encoding.UTF8.GetString(ptr, 4, 2) == "SO")
            {
                if (ct == trFlag)
                {
                    var tmp = new byte[ptr.Length - 4];
                    Array.Copy(ptr, 4, tmp, 0, tmp.Length);
                    return tmp;
                }
                return null;
            }

            var ids = new string[]
            {
                "MThd",
                "FORM",
                "MDhd",
                "MDpg"
            };

            using (var ms = new MemoryStream(ptr))
            {
                var br = new BinaryReader(ms);
                ms.Seek(4, SeekOrigin.Current);
                size = (int)br.ReadUInt32BigEndian();

                // Okay, we're looking for one of those things: either
                // an 'MThd' tag (for SMF), or a 'FORM' tag (for XMIDI).
                size = 48; // Arbitrary; we should find our tag within the first 48 bytes of the resource
                pos = 0;
                while (pos < size)
                {
                    for (int i = 0; i < ids.Length; ++i)
                    {
                        var sig = System.Text.Encoding.UTF8.GetString(br.ReadBytes(4));
                        ms.Seek(-4, SeekOrigin.Current);
                        if ((((int)ct) & (1 << i)) != 0 && (sig == ids[i]))
                        {
                            var tmp = new byte[ptr.Length - ms.Position];
                            Array.Copy(ptr, (int)ms.Position, tmp, 0, tmp.Length);
                            return tmp;
                        }
                    }
                    ++pos; // We could probably iterate more intelligently
                    ms.Seek(1, SeekOrigin.Current);
                }

                if (ct == (ChunkType.MThd | ChunkType.FORM))
                    Debug.WriteLine("IMuseInternal.FindStartOfSound(): Failed to align on sound {0}", sound);
            }

            return null;
        }
Example #12
0
        protected void LoadStartParameters(int sound)
        {
            _priority = 0x80;
            _volume = 0x7F;
            VolChan = 0xFFFF;
            _vol_eff = (byte)((_se.GetChannelVolume(0xFFFF) << 7) >> 7);
            _pan = 0;
            _transpose = 0;
            _detune = 0;

            var ptr = _se.FindStartOfSound(sound, IMuseInternal.ChunkType.MDhd);
            uint size;

            if (ptr != null)
            {
                using (var br = new BinaryReader(new MemoryStream(ptr)))
                {
                    br.BaseStream.Seek(4, SeekOrigin.Current);
                    size = br.ReadUInt32BigEndian();
                    br.BaseStream.Seek(4, SeekOrigin.Current);

                    // MDhd chunks don't get used in MI1 and contain only zeroes.
                    // We check for volume, priority and speed settings of zero here.
                    if (size != 0 && (ptr[2] | ptr[3] | ptr[7]) != 0)
                    {
                        _priority = ptr[2];
                        _volume = ptr[3];
                        _pan = (sbyte)ptr[4];
                        _transpose = (sbyte)ptr[5];
                        _detune = (sbyte)ptr[6];
                        SetSpeed(ptr[7]);
                    }
                }
            }
        }
Example #13
0
        void LoadFont(string filename)
        {
            byte[] dataSrc;
            using (var file = ServiceLocator.FileStorage.OpenFileRead(filename))
            {
                var reader = new BinaryReader(file);
                var tag = System.Text.Encoding.UTF8.GetString(reader.ReadBytes(4));
                if (tag != "ANIM")
                {
                    throw new InvalidOperationException("NutRenderer.LoadFont() there is no ANIM chunk in font header");
                }

                var length = (int)reader.ReadUInt32BigEndian();
                dataSrc = reader.ReadBytes(length);
            }

            if (System.Text.Encoding.UTF8.GetString(dataSrc, 0, 4) != "AHDR")
            {
                throw new InvalidOperationException("NutRenderer::loadFont() there is no AHDR chunk in font header");
            }

            // We pre-decode the font, which may seem wasteful at first. Actually,
            // the memory needed for just the decoded glyphs is smaller than the
            // whole of the undecoded font file.


            _numChars = BitConverter.ToUInt16(dataSrc, 10);
            Debug.Assert(_numChars <= _chars.Length);

            _paletteMap = new byte[256];

            var offset = 0;
            var decodedLength = 0;
            for (var l = 0; l < _numChars; l++)
            {
                offset += (int)ScummHelper.SwapBytes(BitConverter.ToUInt32(dataSrc, offset + 4)) + 16;
                int width = BitConverter.ToUInt16(dataSrc, offset + 14);
                int height = BitConverter.ToUInt16(dataSrc, offset + 16);
                int size = width * height;
                decodedLength += size;
                if (size > _maxCharSize)
                    _maxCharSize = size;
            }

            Debug.WriteLine("NutRenderer::loadFont('{0}') - decodedLength = {1}", filename, decodedLength);

            _decodedData = new byte[decodedLength];
            var decodedPos = 0;

            offset = 0;
            for (var l = 0; l < _numChars; l++)
            {
                offset += (int)ScummHelper.SwapBytes(BitConverter.ToUInt32(dataSrc, offset + 4)) + 8;
                if (System.Text.Encoding.UTF8.GetString(dataSrc, offset, 4) != "FRME")
                {
                    throw new InvalidOperationException(string.Format("NutRenderer::loadFont({0}) there is no FRME chunk {1} (offset {2:X})", filename, l, offset));
                }
                offset += 8;
                if (System.Text.Encoding.UTF8.GetString(dataSrc, offset, 4) != "FOBJ")
                {
                    throw new InvalidOperationException(string.Format("NutRenderer::loadFont({0}) there is no FOBJ chunk in FRME chunk {1} (offset {2:X})", filename, l, offset));
                }
                int codec = BitConverter.ToUInt16(dataSrc, offset + 8);
                // _chars[l].xoffs = READ_LE_UINT16(dataSrc + offset + 10);
                // _chars[l].yoffs = READ_LE_UINT16(dataSrc + offset + 12);
                _chars[l].Width = BitConverter.ToUInt16(dataSrc, offset + 14);
                _chars[l].Height = BitConverter.ToUInt16(dataSrc, offset + 16);
                _chars[l].Src = _decodedData;
                _chars[l].SrcOffset = decodedPos;

                decodedPos += (_chars[l].Width * _chars[l].Height);

                // If characters have transparency, then bytes just get skipped and
                // so there may appear some garbage. That's why we have to fill it
                // with a default color first.
                if (codec == 44)
                {
                    for (int i = 0; i < _chars[l].Width * _chars[l].Height; i++)
                    {
                        _chars[l].Src[_chars[l].SrcOffset + i] = Smush44TransparentColor;
                    }
                    _paletteMap[Smush44TransparentColor] = 1;
                    _chars[l].Transparency = Smush44TransparentColor;
                }
                else
                {
                    for (int i = 0; i < _chars[l].Width * _chars[l].Height; i++)
                    {
                        _chars[l].Src[_chars[l].SrcOffset + i] = DefaultTransparentColor;
                    }
                    _paletteMap[DefaultTransparentColor] = 1;
                    _chars[l].Transparency = DefaultTransparentColor;
                }

                switch (codec)
                {
                    case 1:
                        Codec1(_chars[l].Src, _chars[l].SrcOffset, dataSrc, offset + 22, _chars[l].Width, _chars[l].Height, _chars[l].Width);
                        break;
                    case 21:
                    case 44:
                        Codec21(_chars[l].Src, _chars[l].SrcOffset, dataSrc, offset + 22, _chars[l].Width, _chars[l].Height, _chars[l].Width);
                        break;
                    default:
                        throw new InvalidOperationException(string.Format("NutRenderer::loadFont: unknown codec: {0}", codec));
                }
            }

            // We have decoded the font. Now let's see if we can re-compress it to
            // a more compact format. Start by counting the number of colors.

            int numColors = 0;
            for (var l = 0; l < 256; l++)
            {
                if (_paletteMap[l] != 0)
                {
                    if (numColors < _palette.Length)
                    {
                        _paletteMap[l] = (byte)numColors;
                        _palette[numColors] = (byte)l;
                    }
                    numColors++;
                }
            }

            // Now _palette contains all the used colors, and _paletteMap maps the
            // real color to the palette index.

            if (numColors <= 2)
                _bpp = 1;
            else if (numColors <= 4)
                _bpp = 2;
            else if (numColors <= 16)
                _bpp = 4;
            else
                _bpp = 8;

            if (_bpp < 8)
            {
                int compressedLength = 0;
                for (var l = 0; l < 256; l++)
                {
                    compressedLength += (((_bpp * _chars[l].Width + 7) / 8) * _chars[l].Height);
                }

                Debug.WriteLine("NutRenderer::loadFont('{0}') - compressedLength = {1} ({2} bpp)", filename, compressedLength, _bpp);

                var compressedData = new byte[compressedLength];

                offset = 0;

                for (var l = 0; l < 256; l++)
                {
                    var src = _chars[l].Src;
                    var srcPos = _chars[l].SrcOffset;
                    var dstPos = offset;
                    int srcPitch = _chars[l].Width;
                    int dstPitch = (_bpp * _chars[l].Width + 7) / 8;

                    for (var h = 0; h < _chars[l].Height; h++)
                    {
                        byte bit = 0x80;
                        var nextDst = dstPos + dstPitch;
                        for (int w = 0; w < srcPitch; w++)
                        {
                            byte color = _paletteMap[src[srcPos + w]];
                            for (int i = 0; i < _bpp; i++)
                            {
                                if ((color & (1 << i)) != 0)
                                    compressedData[dstPos] |= bit;
                                bit >>= 1;
                            }
                            if (bit == 0)
                            {
                                bit = 0x80;
                                dstPos++;
                            }
                        }
                        srcPos += srcPitch;
                        dstPos = nextDst;
                    }
                    _chars[l].Src = compressedData;
                    _chars[l].SrcOffset = offset;
                    offset += (dstPitch * _chars[l].Height);
                }

                _decodedData = compressedData;

                _charBuffer = new byte[_maxCharSize];
            }

            _paletteMap = null;
        }
Example #14
0
        void ParseNextFrame()
        {
            string subType;
            uint subSize = 0;
            long subOffset = 0;

            if (_seekPos >= 0)
            {
                if (_smixer != null)
                    _smixer.Stop();

                if (!string.IsNullOrEmpty(_seekFile))
                {
                    _base = new BinaryReader(ServiceLocator.FileStorage.OpenFileRead(_seekFile));
                    _base.ReadUInt32BigEndian();
                    _baseSize = _base.ReadUInt32BigEndian();

                    if (_seekPos > 0)
                    {
                        Debug.Assert(_seekPos > 8);
                        // In this case we need to get palette and number of frames
                        subType = _base.ReadBytes(4).ToText();
                        subSize = _base.ReadUInt32BigEndian();
                        subOffset = _base.BaseStream.Position;
                        Debug.Assert(subType == "AHDR");
                        HandleAnimHeader(subSize, _base);
                        _base.BaseStream.Seek(subOffset + subSize, SeekOrigin.Begin);

                        _middleAudio = true;
                        _seekPos -= 8;
                    }
                    else
                    {
                        // We need this in Full Throttle when entering/leaving
                        // the old mine road.
                        TryCmpFile(_seekFile);
                    }
                    _skipPalette = false;
                }
                else
                {
                    _skipPalette = true;
                }

                _base.BaseStream.Seek(_seekPos + 8, SeekOrigin.Begin);
                _frame = _seekFrame;
                _startFrame = _frame;
                _startTime = Environment.TickCount;

                _seekPos = -1;
            }

            Debug.Assert(_base != null);

            if (_base.BaseStream.Position >= _baseSize)
            {
                _vm.SmushVideoShouldFinish = true;
                _endOfFile = true;
                return;
            }

            subType = _base.ReadBytes(4).ToText();
            subSize = _base.ReadUInt32BigEndian();
            subOffset = _base.BaseStream.Position;

            //            Debug.WriteLine("Chunk: {0} at {1}", subType, subOffset);

            switch (subType)
            {
                case "AHDR": // FT INSANE may seek file to the beginning
                    HandleAnimHeader(subSize, _base);
                    break;
                case "FRME":
                    HandleFrame(subSize, _base);
                    break;
                default:
                    throw new InvalidOperationException(string.Format("Unknown Chunk found at {0:X}: {1}, {2}", subOffset, subType, subSize));
            }

            _base.BaseStream.Seek(subOffset + subSize, SeekOrigin.Begin);

            if (_insanity)
                _vm.Sound.ProcessSound();

            _vm.IMuseDigital.FlushTracks();
        }
Example #15
0
        // Internal mutex-free versions of the IMuse and MusicEngine methods.
        protected bool StartSoundInternal(int sound, int offset = 0)
        {
            // Do not start a sound if it is already set to start on an ImTrigger
            // event. This fixes carnival music problems where a sound has been set
            // to trigger at the right time, but then is started up immediately
            // anyway, only to be restarted later when the trigger occurs.
            //
            // However, we have to make sure the sound with the trigger is actually
            // playing, otherwise the music may stop when Sam and Max are thrown
            // out of Bumpusville, because entering the mansion sets up a trigger
            // for a sound that isn't necessarily playing. This is somewhat related
            // to bug #780918.

            foreach (var trigger in _snm_triggers)
            {
                if (trigger.Sound != 0 && trigger.Id != 0 && trigger.Command[0] == 8 && trigger.Command[1] == sound && GetSoundStatusInternal(trigger.Sound, true) != 0)
                    return false;
            }

            var ptr = FindStartOfSound(sound);
            if (ptr == null)
            {
                Debug.WriteLine("IMuseInternal::startSound(): Couldn't find sound {0}", sound);
                return false;
            }

            // Check which MIDI driver this track should use.
            // If it's NULL, it ain't something we can play.
            var driver = GetBestMidiDriver(sound);
            if (driver == null)
                return false;

            // If the requested sound is already playing, start it over
            // from scratch. This was originally a hack to prevent Sam & Max
            // iMuse messiness while upgrading the iMuse engine, but it
            // is apparently necessary to deal with fade-and-restart
            // race conditions that were observed in MI2. Reference
            // Bug #590511 and Patch #607175 (which was reversed to fix
            // an FOA regression: Bug #622606).
            var player = FindActivePlayer(sound);
            if (player == null)
            {
                ptr = FindStartOfSound(sound, ChunkType.MDhd);
                int size = 128;
                if (ptr != null)
                {
                    using (var br = new BinaryReader(new MemoryStream(ptr)))
                    {
                        br.BaseStream.Seek(4, SeekOrigin.Begin);
                        var tmp = br.ReadUInt32BigEndian();
                        size = tmp != 0 && ptr[10] != 0 ? ptr[10] : 128;
                    }
                }
                player = AllocatePlayer((byte)size);
            }

            if (player == null)
                return false;

            // WORKAROUND: This is to work around a problem at the Dino Bungie
            // Memorial.
            //
            // There are three pieces of music involved here:
            //
            // 80 - Main theme (looping)
            // 81 - Music when entering Rex's and Wally's room (not looping)
            // 82 - Music when listening to Rex or Wally
            //
            // When entering, tune 81 starts, tune 80 is faded down (not out) and
            // a trigger is set in tune 81 to fade tune 80 back up.
            //
            // When listening to Rex or Wally, tune 82 is started, tune 81 is faded
            // out and tune 80 is faded down even further.
            //
            // However, when tune 81 is faded out its trigger will cause tune 80 to
            // fade back up, resulting in two tunes being played simultaneously at
            // full blast. It's no use trying to keep tune 81 playing at volume 0.
            // It doesn't loop, so eventually it will terminate on its own.
            //
            // I don't know how the original interpreter handled this - or even if
            // it handled it at all - but it looks like sloppy scripting to me. Our
            // workaround is to clear the trigger if the player listens to Rex or
            // Wally before tune 81 has finished on its own.

            if (_game_id == GameId.SamNMax && sound == 82 && GetSoundStatusInternal(81, false) != 0)
                ImClearTrigger(81, 1);

            player.Clear();
            player.SetOffsetNote(offset);
            return player.StartSound(sound, driver);
        }
Example #16
0
        protected override void LoadIndex(GameInfo game)
        {
            Directory = ServiceLocator.FileStorage.GetDirectoryName(game.Path);
            using (var file = ServiceLocator.FileStorage.OpenFileRead(game.Path))
            {
                var br = new BinaryReader(file);
                while (br.BaseStream.Position < br.BaseStream.Length)
                {
                    var tag = System.Text.Encoding.UTF8.GetString(br.ReadBytes(4));
                    br.ReadUInt32BigEndian();

                    switch (tag)
                    {
                        case "DCHR":
                        case "DIRF":
                            var charset = ReadResTypeList(br);
                            CharsetResources = new ReadOnlyCollection<Resource>(charset);
                            break;

                        case "DOBJ":
                            ReadDirectoryOfObjects(br);
                            break;

                        case "RNAM":
                            ReadRoomNames(br);
                            break;

                        case "DROO":
                        case "DIRR":
                            var rooms = ReadResTypeList(br);
                            RoomResources = new ReadOnlyCollection<Resource>(rooms);
                            break;

                        case "DSCR":
                        case "DIRS":
                            var scripts = ReadResTypeList(br);
                            ScriptResources = new ReadOnlyCollection<Resource>(scripts);
                            break;

                        case "DRSC":
                            var roomScripts = ReadResTypeList(br);
                            RoomScriptResources = new ReadOnlyCollection<Resource>(roomScripts);
                            break;

                        case "DCOS":
                        case "DIRC":
                            var costumes = ReadResTypeList(br);
                            CostumeResources = new ReadOnlyCollection<Resource>(costumes);
                            break;

                        case "MAXS":
                            ReadMaxSizes(br);
                            break;

                        case "DIRN":
                        case "DSOU":
                            var sounds = ReadResTypeList(br);
                            SoundResources = new ReadOnlyCollection<Resource>(sounds);
                            break;

                        case "AARY":
                            ReadArrayFromIndexFile(br);
                            break;

                        case "ANAM":        // Used by: The Dig, FT
                            {
                                var num = br.ReadUInt16();
                                AudioNames = new string[num];
                                for (int i = 0; i < num; i++)
                                {
									AudioNames[i] = br.ReadBytes(9).GetText();
                                }
                            }
                            break;

//                        default:
//                            Console.Error.WriteLine("Unknown tag {0} found in index file directory", tag);
//                            break;
                    }
                }
            }
        }
Example #17
0
        MdatResource LoadMdatFile(Stream musicData)
        {
            var br = new BinaryReader(musicData);
            bool hasHeader = false;
            var mdatSize = musicData.Length;
            if (mdatSize >= 0x200)
            {

                // 0x0000: 10 Bytes Header "TFMX-SONG "
                var buf = System.Text.Encoding.UTF8.GetString(br.ReadBytes(10));
                hasHeader = buf == "TFMX-SONG ";
            }

            if (!hasHeader)
            {
                Debug.WriteLine("Tfmx: File is not a Tfmx Module");
                return null;
            }

            var resource = new MdatResource();

            resource.mdatAlloc = null;
            resource.mdatOffset = 0;
            resource.mdatLen = 0;

            // 0x000A: int16 flags
            resource.headerFlags = br.ReadUInt16BigEndian();
            // 0x000C: int32 ?
            // 0x0010: 6*40 Textfield
            musicData.Seek(4 + 6 * 40, SeekOrigin.Current);

            /* 0x0100: Songstart x 32*/
            for (int i = 0; i < NumSubsongs; ++i)
                resource.subsong[i].songstart = br.ReadUInt16BigEndian();
            /* 0x0140: Songend x 32*/
            for (int i = 0; i < NumSubsongs; ++i)
                resource.subsong[i].songend = br.ReadUInt16BigEndian();
            /* 0x0180: Tempo x 32*/
            for (int i = 0; i < NumSubsongs; ++i)
                resource.subsong[i].tempo = br.ReadUInt16BigEndian();

            /* 0x01c0: unused ? */
            musicData.Seek(16, SeekOrigin.Current);

            /* 0x01d0: trackstep, pattern data p, macro data p */
            var offTrackstep = br.ReadUInt32BigEndian();
            uint offPatternP, offMacroP;

            // This is how MI`s TFMX-Player tests for unpacked Modules.
            if (offTrackstep == 0)
            { // unpacked File
                resource.trackstepOffset = 0x600 + 0x200;
                offPatternP = 0x200 + 0x200;
                offMacroP = 0x400 + 0x200;
            }
            else
            { // packed File
                resource.trackstepOffset = offTrackstep;
                offPatternP = br.ReadUInt32BigEndian();
                offMacroP = br.ReadUInt32BigEndian();
            }

            // TODO: if a File is packed it could have for Ex only 2 Patterns/Macros
            // the following loops could then read beyond EOF.
            // To correctly handle this it would be necessary to sort the pointers and
            // figure out the number of Macros/Patterns
            // We could also analyze pointers if they are correct offsets,
            // so that accesses can be unchecked later

            // Read in pattern starting offsets
            musicData.Seek(offPatternP, SeekOrigin.Begin);
            for (int i = 0; i < MaxPatternOffsets; ++i)
                resource.patternOffset[i] = br.ReadUInt32BigEndian();

            // use last PatternOffset (stored at 0x5FC in mdat) if unpacked File
            // or fixed offset 0x200 if packed
            resource.sfxTableOffset = offTrackstep != 0 ? 0x200 : resource.patternOffset[127];

            // Read in macro starting offsets
            musicData.Seek(offMacroP, SeekOrigin.Begin);
            for (int i = 0; i < MaxMacroOffsets; ++i)
                resource.macroOffset[i] = br.ReadUInt32BigEndian();

            // Read in mdat-file
            // TODO: we can skip everything thats already stored in the resource-structure.
            var mdatOffset = offTrackstep != 0 ? 0x200 : 0x600;  // 0x200 is very conservative
            var allocSize = mdatSize - mdatOffset;

            musicData.Seek(mdatOffset, SeekOrigin.Begin);
            var mdatAlloc = br.ReadBytes((int)allocSize);

            resource.mdatAlloc = mdatAlloc;
            resource.mdatOffset = mdatOffset;
            resource.mdatLen = (int)mdatSize;
            return resource;
        }
Example #18
0
        public override bool LoadStream(Stream stream)
        {
            Close();

            _fileStream = stream;
            _br = new BinaryReader(stream);

            // Read in the Smacker header
            _header = new Header();
            _header.signature = _br.ReadUInt32BigEndian();

            if (_header.signature != ScummHelper.MakeTag('S', 'M', 'K', '2') && _header.signature != ScummHelper.MakeTag('S', 'M', 'K', '4'))
                return false;

            uint width = _br.ReadUInt32();
            uint height = _br.ReadUInt32();
            uint frameCount = _br.ReadUInt32();
            int frameDelay = _br.ReadInt32();

            // frame rate contains 2 digits after the comma, so 1497 is actually 14.97 fps
            Rational frameRate;
            if (frameDelay > 0)
                frameRate = new Rational(1000, frameDelay);
            else if (frameDelay < 0)
                frameRate = new Rational(100000, -frameDelay);
            else
                frameRate = new Rational(1000);

            // Flags are determined by which bit is set, which can be one of the following:
            // 0 - set to 1 if file contains a ring frame.
            // 1 - set to 1 if file is Y-interlaced
            // 2 - set to 1 if file is Y-doubled
            // If bits 1 or 2 are set, the frame should be scaled to twice its height
            // before it is displayed.
            _header.flags = _br.ReadUInt32();

            var videoTrack = CreateVideoTrack(width, height, frameCount, frameRate, _header.flags, _header.signature);
            AddTrack(videoTrack);

            // TODO: should we do any extra processing for Smacker files with ring frames?

            // TODO: should we do any extra processing for Y-doubled videos? Are they the
            // same as Y-interlaced videos?

            uint i;
            for (i = 0; i < 7; ++i)
                _header.audioSize[i] = _br.ReadUInt32();

            _header.treesSize = _br.ReadUInt32();
            _header.mMapSize = _br.ReadUInt32();
            _header.mClrSize = _br.ReadUInt32();
            _header.fullSize = _br.ReadUInt32();
            _header.typeSize = _br.ReadUInt32();

            for (i = 0; i < 7; ++i)
            {
                // AudioRate - Frequency and format information for each sound track, up to 7 audio tracks.
                // The 32 constituent bits have the following meaning:
                // * bit 31 - indicates Huffman + Dpcm compression
                // * bit 30 - indicates that audio data is present for this track
                // * bit 29 - 1 = 16-bit audio; 0 = 8-bit audio
                // * bit 28 - 1 = stereo audio; 0 = mono audio
                // * bit 27 - indicates Bink Rdft compression
                // * bit 26 - indicates Bink Dct compression
                // * bits 25-24 - unused
                // * bits 23-0 - audio sample rate
                uint audioInfo = _br.ReadUInt32();
                _header.audioInfo[i].hasAudio = (audioInfo & 0x40000000) != 0;
                _header.audioInfo[i].is16Bits = (audioInfo & 0x20000000) != 0;
                _header.audioInfo[i].isStereo = (audioInfo & 0x10000000) != 0;
                _header.audioInfo[i].sampleRate = audioInfo & 0xFFFFFF;

                if ((audioInfo & 0x8000000) != 0)
                    _header.audioInfo[i].compression = AudioCompression.Rdft;
                else if ((audioInfo & 0x4000000) != 0)
                    _header.audioInfo[i].compression = AudioCompression.Dct;
                else if ((audioInfo & 0x80000000) != 0)
                    _header.audioInfo[i].compression = AudioCompression.Dpcm;
                else
                    _header.audioInfo[i].compression = AudioCompression.None;

                if (_header.audioInfo[i].hasAudio)
                {
                    if (_header.audioInfo[i].compression == AudioCompression.Rdft || _header.audioInfo[i].compression == AudioCompression.Dct)
                        throw new InvalidOperationException("Unhandled Smacker v2 audio compression");

                    AddTrack(new SmackerAudioTrack(_mixer, _header.audioInfo[i], _soundType));
                }
            }

            _header.dummy = _br.ReadUInt32();

            _frameSizes = new uint[frameCount];
            for (i = 0; i < frameCount; ++i)
                _frameSizes[i] = _br.ReadUInt32();

            _frameTypes = new byte[frameCount];
            for (i = 0; i < frameCount; ++i)
                _frameTypes[i] = _br.ReadByte();

            var huffmanTrees = _br.ReadBytes((int)_header.treesSize);
            using (var ms = new MemoryStream(huffmanTrees))
            {
                var bs = BitStream.Create8Lsb(ms);
                videoTrack.ReadTrees(bs, (int)_header.mMapSize, (int)_header.mClrSize, (int)_header.fullSize, (int)_header.typeSize);
            }

            _firstFrameStart = (uint)_fileStream.Position;

            return true;
        }
Example #19
0
        public bool RestoreGameFromFile(byte slot)
        {

            ushort cnt;
            var fName = $"sword1.{slot:D3}";
            using (var inf = new BinaryReader(_saveFileMan.OpenForLoading(fName)))
            {
                // TODO:
                //if (inf==null)
                //{
                //    // Display an error message, and do nothing
                //    // TODO: DisplayMessage(0, "Can't open file '%s'. (%s)", fName, _saveFileMan.popErrorDesc().c_str());
                //    return false;
                //}

                uint saveHeader = inf.ReadUInt32();
                if (saveHeader != SAVEGAME_HEADER)
                {
                    // Display an error message, and do nothing
                    // TODO: DisplayMessage(0, "Save game '%s' is corrupt", fName);
                    return false;
                }

                inf.BaseStream.Seek(40, SeekOrigin.Current); // skip description
                byte saveVersion = inf.ReadByte();

                if (saveVersion > SAVEGAME_VERSION)
                {
                    // TODO: warning("Different save game version");
                    return false;
                }

                if (saveVersion < 2) // These older version of the savegames used a flag to signal presence of thumbnail
                    inf.BaseStream.Seek(1, SeekOrigin.Current);

                SkipThumbnail(inf);

                inf.ReadUInt32BigEndian(); // save date
                inf.ReadUInt16BigEndian(); // save time

                if (saveVersion < 2)
                {
                    // Before version 2 we didn't had play time feature
                    // TODO: g_engine.setTotalPlayTime(0);
                }
                else
                {
                    var time = inf.ReadUInt32BigEndian();
                    // TODO: g_engine.setTotalPlayTime(time * 1000);
                }

                _restoreBuf = new byte[
                    ObjectMan.TOTAL_SECTIONS * 2 +
                    Logic.NUM_SCRIPT_VARS * 4 +
                    (SwordObject.Size - 12000)];

                var liveBuf = new UShortAccess(_restoreBuf);
                var scriptBuf = new UIntAccess(_restoreBuf, 2 * ObjectMan.TOTAL_SECTIONS);
                var playerBuf = new UIntAccess(_restoreBuf, 2 * ObjectMan.TOTAL_SECTIONS + 4 * Logic.NUM_SCRIPT_VARS);

                for (cnt = 0; cnt < ObjectMan.TOTAL_SECTIONS; cnt++)
                    liveBuf[cnt] = inf.ReadUInt16();

                for (cnt = 0; cnt < Logic.NUM_SCRIPT_VARS; cnt++)
                    scriptBuf[cnt] = inf.ReadUInt32();

                uint playerSize = (SwordObject.Size - 12000) / 4;
                for (var cnt2 = 0; cnt2 < playerSize; cnt2++)
                    playerBuf[cnt2] = inf.ReadUInt32();

                // TODO: error
                //if (inf.err() || inf.eos())
                //{
                //    displayMessage(0, "Can't read from file '%s'. (%s)", fName, _saveFileMan.popErrorDesc().c_str());
                //    delete inf;
                //    free(_restoreBuf);
                //    _restoreBuf = NULL;
                //    return false;
                //}
            }

            return true;
        }
Example #20
0
        public int MatchFile(string filename)
        {
            int offset;
            bool found = false;
            int freeSlot = -1;
            int fileId;

            for (fileId = 0; fileId < _budleDirCache.Length; fileId++)
            {
                if ((_budleDirCache[fileId].BundleTable == null) && (freeSlot == -1))
                {
                    freeSlot = fileId;
                }
                if (string.Equals(filename, _budleDirCache[fileId].FileName, StringComparison.OrdinalIgnoreCase))
                {
                    found = true;
                    break;
                }
            }

            if (!found)
            {
                var file = new BinaryReader(ServiceLocator.FileStorage.OpenFileRead(filename));

//                if (freeSlot == -1)
//                    Console.Error.WriteLine("BundleDirCache::matchFileFile() Can't find free slot for file bundle dir cache");

                var tag = file.ReadTag();
                if (tag == "LB23")
                    _budleDirCache[freeSlot].IsCompressed = true;
                offset = (int)file.ReadUInt32BigEndian();

                _budleDirCache[freeSlot].FileName = filename;
                _budleDirCache[freeSlot].NumFiles = (int)file.ReadUInt32BigEndian();
                _budleDirCache[freeSlot].BundleTable = CreateAudioTable(_budleDirCache[freeSlot].NumFiles);

                file.BaseStream.Seek(offset, SeekOrigin.Begin);

                _budleDirCache[freeSlot].IndexTable = CreateIndexTable(_budleDirCache[freeSlot].NumFiles);

                for (int i = 0; i < _budleDirCache[freeSlot].NumFiles; i++)
                {
                    var name = new List<byte>();
                    byte c;

                    if (tag == "LB23")
                    {
						_budleDirCache[freeSlot].BundleTable[i].Filename = file.ReadBytes(24).GetText();
                    }
                    else
                    {
                        for (var z2 = 0; z2 < 8; z2++)
                            if ((c = file.ReadByte()) != 0)
                                name.Add(c);
                        name.Add((byte)'.');
                        for (var z2 = 0; z2 < 4; z2++)
                            if ((c = file.ReadByte()) != 0)
                                name.Add(c);

						_budleDirCache[freeSlot].BundleTable[i].Filename = name.ToArray().GetText();
                    }
                    _budleDirCache[freeSlot].BundleTable[i].Offset = (int)file.ReadUInt32BigEndian();
                    _budleDirCache[freeSlot].BundleTable[i].Size = (int)file.ReadUInt32BigEndian();
                    _budleDirCache[freeSlot].IndexTable[i].Filename = _budleDirCache[freeSlot].BundleTable[i].Filename;
                    _budleDirCache[freeSlot].IndexTable[i].Index = i;
                }

                Array.Sort(_budleDirCache[freeSlot].IndexTable, new Comparison<IndexNode>((x, y) =>
                        string.Compare(x.Filename, y.Filename, StringComparison.OrdinalIgnoreCase)));

                return freeSlot;
            }
            return fileId;
        }
Example #21
0
        void HandleFrame(uint frameSize, BinaryReader b)
        {
            //            Debug.WriteLine("SmushPlayer.HandleFrame({0})", _frame);
            _skipNext = false;

            if (_insanity)
            {
                _vm.Insane.ProcPreRendering();
            }

            while (frameSize > 0)
            {
                var subType = _base.ReadBytes(4).ToText();
                var subSize = b.ReadUInt32BigEndian();
                var subOffset = b.BaseStream.Position;
                switch (subType)
                {
                    case "NPAL":
                        HandleNewPalette(subSize, b);
                        break;
                    case "FOBJ":
                        HandleFrameObject(subSize, b);
                        break;
#if USE_ZLIB
                    case "ZFOB":
                        HandleZlibFrameObject(subSize, b);
                        break;
#endif
                    case "PSAD":
                        if (!_compressedFileMode)
                            HandleSoundFrame(subSize, b);
                        break;
                    case "TRES":
                        HandleTextResource(subType, subSize, b);
                        break;
                    case "XPAL":
                        HandleDeltaPalette(subSize, b);
                        break;
                    case "IACT":
                        HandleIACT(subSize, b);
                        break;
                    case "STOR":
                        HandleStore(subSize, b);
                        break;
                    case "FTCH":
                        HandleFetch(subSize, b);
                        break;
                    case "SKIP":
                        _vm.Insane.ProcSKIP((int)subSize, b);
                        break;
                    case "TEXT":
                        HandleTextResource(subType, subSize, b);
                        break;
                    default:
                        throw new InvalidOperationException(string.Format("Unknown frame subChunk found : {0}, {1}", subType, subSize));
                }

                frameSize -= subSize + 8;
                b.BaseStream.Seek(subOffset + subSize, SeekOrigin.Begin);
                if ((subSize & 1) != 0)
                {
                    b.BaseStream.Seek(1, SeekOrigin.Current);
                    frameSize--;
                }
            }

            if (_insanity)
            {
                _vm.Insane.ProcPostRendering(_dst, 0, 0, 0, _frame, _nbframes - 1);
            }

            if (_width != 0 && _height != 0)
            {
                UpdateScreen();
            }
            _smixer.HandleFrame();

            _frame++;
        }
Example #22
0
        // Sequencer part
        protected int StartSeqSound(int sound, bool resetVars = true)
        {
            if (resetVars)
            {
                _loop_to_beat = 1;
                _loop_from_beat = 1;
                _track_index = 0;
                _loop_counter = 0;
                _loop_to_tick = 0;
                _loop_from_tick = 0;
            }

            var ptr = _se.FindStartOfSound(sound);
            if (ptr == null)
                return -1;

            if (Encoding.UTF8.GetString(ptr, 0, 2) == "RO")
            {
                // Old style 'RO' resource
                _parser = MidiParser.CreateRO();
            }
            else if (Encoding.UTF8.GetString(ptr, 0, 4) == "FORM")
            {
                // Humongous Games XMIDI resource
                _parser = MidiParser.CreateXMidiParser();
            }
            else
            {
                // SCUMM SMF resource
                _parser = MidiParser.CreateSmfParser();
            }

            _parser.MidiDriver = this;
            _parser.Property(MidiParserProperty.SmartJump, 1);
            _parser.LoadMusic(ptr);
            _parser.ActiveTrack = _track_index;

            ptr = _se.FindStartOfSound(sound, IMuseInternal.ChunkType.MDhd);
            var speed = 128;
            if (resetVars)
            {
                if (ptr != null)
                {
                    using (var br = new BinaryReader(new MemoryStream(ptr)))
                    {
                        br.BaseStream.Seek(4, SeekOrigin.Begin);
                        speed = br.ReadUInt32BigEndian() != 0 && ptr[15] != 0 ? ptr[15] : 128;
                    }
                }
            }
            else
            {
                speed = _speed;
            }
            SetSpeed((byte)speed);

            return 0;
        }