| SITE ANNOUNCEMENTS: | |
|---|---|
| |
User:Markavian/CMV file format
From Dwarf Fortress Wiki
This page is related to the CMV File format. The code below is a C# class for reading CMV files recorded from Dwarf Fortress (Tested 2008-09-11). I can't think of a license to put on it, but feel free to make use of it for non-comercial community related software; for example, I'm working on a CMV Editor at the moment.
Code below is based on work by SL (ShadowLord) and gamecode for writing CMV files forwarded by ToadyOne.
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using ICSharpCode.SharpZipLib;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
namespace CMVData
{
public class CMV
{
const int NUM_SOUNDCHANNELS = 64;
string file;
List<byte[]> frames;
uint version;
uint cols;
uint rows;
uint delayRate;
int numSounds;
byte[] soundNames;
byte[] soundTimings;
public CMV()
{
frames = new List<byte[]>();
}
public CMV(string filename)
{
file = filename;
frames = new List<byte[]>();
readCMV(file);
}
private void readCMV(string inFilename)
{
checkExtension(inFilename);
FileStream stream = File.OpenRead(inFilename);
frames = new List<byte[]>();
byte[] intBytes = new byte[4];
stream.Read(intBytes, 0, 4);
version = BitConverter.ToUInt32(intBytes, 0);
stream.Read(intBytes, 0, 4);
cols = BitConverter.ToUInt32(intBytes, 0);
stream.Read(intBytes, 0, 4);
rows = BitConverter.ToUInt32(intBytes, 0);
stream.Read(intBytes, 0, 4);
delayRate = BitConverter.ToUInt32(intBytes, 0);
// Sounds
if (version == 10001)
{
stream.Read(intBytes, 0, 4);
numSounds = BitConverter.ToInt32(intBytes, 0);
soundNames = new byte[50 * numSounds];
stream.Read(soundNames, 0, 50 * numSounds);
soundTimings = new byte[200 * NUM_SOUNDCHANNELS]; // 0x3200
stream.Read(soundTimings, 0, 200 * NUM_SOUNDCHANNELS);
}
int frameSize = (int)(cols * rows);
frameSize += frameSize;
byte[] previousFrame = new byte[frameSize];
for (int frameByte = 0; frameByte < frameSize; frameByte++)
{
previousFrame[frameByte] = 0;
}
byte[] curFrame = new byte[frameSize];
int framesDone = 0;
int frameSizeLeft = frameSize;
int frameSizeDone = 0;
while (stream.Position < stream.Length)
{
if (stream.Read(intBytes, 0, 4) == 4)
{
int compressedChunkSize = BitConverter.ToInt32(intBytes, 0);
byte[] buffer = new byte[compressedChunkSize];
stream.Read(buffer, 0, compressedChunkSize);
MemoryStream memoryStream = new MemoryStream(buffer);
InflaterInputStream zipZipInStream = new InflaterInputStream(memoryStream);
int bytesRead = 0;
do
{
bytesRead = zipZipInStream.Read(curFrame, frameSizeDone, frameSizeLeft);
frames.Add((byte[])curFrame.Clone());
if (bytesRead == frameSizeLeft)
{
/*
* Valid variables at this point:
* frameSize
* byte[frameSize] previousFrame
* byte[frameSize] curFrame
*/
framesDone++;
Array.Copy(curFrame, previousFrame, frameSize);
frameSizeLeft = frameSize;
frameSizeDone = 0;
}
else
{
frameSizeDone += bytesRead;
frameSizeLeft -= bytesRead;
}
} while (bytesRead == frameSize);
}
else
{
break;
}
}
stream.Close();
stream.Dispose();
}
private void checkExtension(string filename)
{
if (filename.EndsWith(".cmv"))
{
// that's good
}
else if (filename.EndsWith(".ccmv"))
{
// that's possibly good
}
else
{
throw new CMVException("The supplied file type extension is not supported.");
}
}
/* Public methods */
public byte[] CloneFrame(int frameNumber)
{
byte[] frame;
int frameSize;
frameSize = (int)(rows * cols) << 2;
frame = new byte[frameSize];
frames[frameNumber].CopyTo(frame, 0);
return frame;
}
/* Public properties */
public byte[] Frame(int frameNumber)
{
if (frameNumber >= 0 && frameNumber < frames.Count)
{
return frames[frameNumber];
}
throw new CMVException("Frame number (" + frameNumber + ") out of bounds, maximum count " + frames.Count);
}
public string FilePath
{
get { return file; }
}
public string Filename
{
get {
string[] raw = file.Split('\\');
return raw[raw.Length - 1];
}
}
public uint Frames
{
get { return (uint)frames.Count; }
}
public uint Version
{
get { return version; }
}
public uint Columns
{
get { return cols; }
}
public uint Rows
{
get { return rows; }
}
public int Sounds
{
get { return numSounds; }
}
}
}