]> git.tdb.fi Git - libs/datafile.git/blob - source/rawdata.cpp
Recognize and handle raw data files in the data tool
[libs/datafile.git] / source / rawdata.cpp
1 #include <cstring>
2 #include <stdexcept>
3 #include <msp/io/zlibcompressed.h>
4 #include "collection.h"
5 #include "except.h"
6 #include "rawdata.h"
7
8 using namespace std;
9
10 namespace Msp {
11 namespace DataFile {
12
13 const char RawData::signature[4] = { 'M', 'D', 'R', 1 };
14
15 RawData::~RawData()
16 {
17         delete owned_data;
18         delete compressed;
19         if(in_owned)
20                 delete in;
21 }
22
23 bool RawData::detect_signature(const std::string &sig)
24 {
25         return !sig.compare(0, string::npos, signature, sizeof(signature));
26 }
27
28 void RawData::open_file(Collection &coll, const string &fn)
29 {
30         if(in)
31                 throw logic_error("input already exists");
32
33         RefPtr<IO::Base> opened = coll.open_raw(fn);
34         if(!opened)
35                 throw IO::file_not_found(fn);
36
37         open_io(*opened, fn);
38         opened.release();
39         in_owned = true;
40 }
41
42 void RawData::open_io(IO::Base &i, const string &fn)
43 {
44         if(in)
45                 throw logic_error("input already exists");
46
47         char header[14];
48         unsigned len = i.read(header, sizeof(header));
49         if(len!=sizeof(header))
50                 throw data_error(fn, 0, "Missing header");
51         if(memcmp(header, signature, sizeof(signature)))
52                 throw data_error(fn, 0, "Bad header");
53
54         size = 0;
55         for(unsigned j=0; j<8; ++j)
56                 size = (size<<8) | static_cast<unsigned char>(header[4+j]);
57
58         uint16_t flags = (static_cast<unsigned char>(header[12])<<8) | static_cast<unsigned char>(header[13]);
59
60         src_name = fn;
61         in = &i;
62         if(flags&COMPRESSED)
63                 compressed = new IO::ZlibCompressed(*in, IO::M_READ);
64 }
65
66 void RawData::load()
67 {
68         if(!in)
69                 throw logic_error("no input");
70         if(data)
71                 throw logic_error("already loaded");
72
73         owned_data = new char[size];
74         load_into(owned_data);
75 }
76
77 void RawData::load_into(void *buffer)
78 {
79         if(!in)
80                 throw logic_error("no input");
81
82         data = static_cast<char *>(buffer);
83
84         IO::Base *src = (compressed ? compressed : in);
85         size_t pos = 0;
86         while(pos<size)
87         {
88                 size_t len = src->read(data+pos, size-pos);
89                 if(!len)
90                         throw data_error(src_name, 0, "Truncated data");
91                 pos += len;
92         }
93
94         if(in_owned)
95                 delete in;
96         in = nullptr;
97 }
98
99 void RawData::write_io(IO::Base &io, bool compress)
100 {
101         if(!data)
102                 throw logic_error("no data");
103
104         io.write(signature, sizeof(signature));
105
106         for(unsigned i=56; i<64; i-=8)
107                 io.put((size>>i)&0xFF);
108
109         uint16_t flags = 0;
110         if(compress)
111                 flags |= COMPRESSED;
112         io.put((flags>>8)&0xFF);
113         io.put(flags&0xFF);
114
115         if(compress)
116         {
117                 IO::ZlibCompressed z(io, IO::M_WRITE);
118                 z.write(data, size);
119         }
120         else
121                 io.write(data, size);
122 }
123
124 } // namespace DataFile
125 } // namespace Msp