+#include <stdexcept>
+#include <msp/io/zlibcompressed.h>
+#include "collection.h"
+#include "except.h"
+#include "rawdata.h"
+
+using namespace std;
+
+namespace Msp {
+namespace DataFile {
+
+RawData::~RawData()
+{
+ delete owned_data;
+ delete compressed;
+ if(in_owned)
+ delete in;
+}
+
+void RawData::open_file(Collection &coll, const string &fn)
+{
+ if(in)
+ throw logic_error("input already exists");
+
+ RefPtr<IO::Base> opened = coll.open_raw(fn);
+ if(!opened)
+ throw IO::file_not_found(fn);
+
+ open_io(*opened, fn);
+ opened.release();
+ in_owned = true;
+}
+
+void RawData::open_io(IO::Base &i, const string &fn)
+{
+ if(in)
+ throw logic_error("input already exists");
+
+ char header[14];
+ unsigned len = i.read(header, sizeof(header));
+ if(len!=sizeof(header))
+ throw data_error(fn, 0, "Missing header");
+ if(header[0]!='M' || header[1]!='D' || header[2]!='R' || header[3]!=1)
+ throw data_error(fn, 0, "Bad header");
+
+ size = 0;
+ for(unsigned j=0; j<8; ++j)
+ size = (size<<8) | static_cast<unsigned char>(header[4+j]);
+
+ uint16_t flags = (static_cast<unsigned char>(header[12])<<8) | static_cast<unsigned char>(header[13]);
+
+ src_name = fn;
+ in = &i;
+ if(flags&COMPRESSED)
+ compressed = new IO::ZlibCompressed(*in, IO::M_READ);
+}
+
+void RawData::load()
+{
+ if(!in)
+ throw logic_error("no input");
+ if(data)
+ throw logic_error("already loaded");
+
+ owned_data = new char[size];
+ load_into(owned_data);
+}
+
+void RawData::load_into(void *buffer)
+{
+ if(!in)
+ throw logic_error("no input");
+
+ data = static_cast<char *>(buffer);
+
+ IO::Base *src = (compressed ? compressed : in);
+ size_t pos = 0;
+ while(pos<size)
+ {
+ size_t len = src->read(data+pos, size-pos);
+ if(!len)
+ throw data_error(src_name, 0, "Truncated data");
+ pos += len;
+ }
+
+ if(in_owned)
+ delete in;
+ in = nullptr;
+}
+
+} // namespace DataFile
+} // namespace Msp