Extend basic support for serializing simple data types.
[cumulus.git] / store.cc
1 /* LBS: An LFS-inspired filesystem backup system
2  * Copyright (C) 2006  Michael Vrable
3  *
4  * Backup data is stored in a collection of objects, which are grouped together
5  * into segments for storage purposes.  This file provides interfaces for
6  * reading and writing objects and segments. */
7
8 #include <assert.h>
9
10 #include "store.h"
11
12 using std::string;
13
14 void OutputStream::write_u8(uint8_t val)
15 {
16     write(&val, 1);
17 }
18
19 void OutputStream::write_u16(uint16_t val)
20 {
21     unsigned char buf[2];
22
23     buf[0] = val & 0xff;
24     buf[1] = (val >> 8) & 0xff;
25     write(buf, 2);
26 }
27
28 void OutputStream::write_u32(uint32_t val)
29 {
30     unsigned char buf[4];
31
32     buf[0] = val & 0xff;
33     buf[1] = (val >> 8) & 0xff;
34     buf[2] = (val >> 16) & 0xff;
35     buf[3] = (val >> 24) & 0xff;
36     write(buf, 4);
37 }
38
39 void OutputStream::write_u64(uint64_t val)
40 {
41     unsigned char buf[8];
42
43     buf[0] = val & 0xff;
44     buf[1] = (val >> 8) & 0xff;
45     buf[2] = (val >> 16) & 0xff;
46     buf[3] = (val >> 24) & 0xff;
47     buf[4] = (val >> 32) & 0xff;
48     buf[5] = (val >> 40) & 0xff;
49     buf[6] = (val >> 48) & 0xff;
50     buf[7] = (val >> 56) & 0xff;
51     write(buf, 8);
52 }
53
54 /* Writes an integer to an output stream using a variable-sized representation:
55  * seven bits are written at a time (little-endian), and the eigth bit of each
56  * byte is set if more data follows. */
57 void OutputStream::write_varint(uint64_t val)
58 {
59     do {
60         uint8_t remainder = (val & 0x7f);
61         val >>= 7;
62         if (val)
63             remainder |= 0x80;
64         write_u8(remainder);
65     } while (val);
66 }
67
68 /* Write an arbitrary string by first writing out the length, followed by the
69  * data itself. */
70 void OutputStream::write_string(const string &s)
71 {
72     size_t len = s.length();
73     write_varint(len);
74     write(s.data(), len);
75 }
76
77 void OutputStream::write_dictionary(const dictionary &d)
78 {
79     size_t size = d.size();
80     size_t written = 0;
81
82     write_varint(size);
83
84     for (dictionary::const_iterator i = d.begin(); i != d.end(); ++i) {
85         write_string(i->first);
86         write_string(i->second);
87         written++;
88     }
89
90     assert(written == size);
91 }
92
93 StringOutputStream::StringOutputStream()
94     : buf(std::ios_base::out)
95 {
96 }
97
98 void StringOutputStream::write(const void *data, size_t len)
99 {
100     buf.write((const char *)data, len);
101     if (!buf.good())
102         throw IOException("error writing to StringOutputStream");
103 }
104
105 FileOutputStream::FileOutputStream(FILE *file)
106 {
107     f = file;
108 }
109
110 FileOutputStream::~FileOutputStream()
111 {
112     fclose(f);
113 }
114
115 void FileOutputStream::write(const void *data, size_t len)
116 {
117     size_t res;
118
119     res = fwrite(data, 1, len, f);
120     if (res != len) {
121         throw IOException("write error");
122     }
123 }
124
125 /* Utility functions, for encoding data types to strings. */
126 string encode_u16(uint16_t val)
127 {
128     StringOutputStream s;
129     s.write_u16(val);
130     return s.contents();
131 }
132
133 string encode_u32(uint32_t val)
134 {
135     StringOutputStream s;
136     s.write_u32(val);
137     return s.contents();
138 }
139
140 string encode_u64(uint64_t val)
141 {
142     StringOutputStream s;
143     s.write_u64(val);
144     return s.contents();
145 }