Improve comments, and track number of bytes written to a stream.
[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 OutputStream::OutputStream()
15     : bytes_written(0)
16 {
17 }
18
19 void OutputStream::write(const void *data, size_t len)
20 {
21     write_internal(data, len);
22     bytes_written += len;
23 }
24
25 void OutputStream::write_u8(uint8_t val)
26 {
27     write(&val, 1);
28 }
29
30 void OutputStream::write_u16(uint16_t val)
31 {
32     unsigned char buf[2];
33
34     buf[0] = val & 0xff;
35     buf[1] = (val >> 8) & 0xff;
36     write(buf, 2);
37 }
38
39 void OutputStream::write_u32(uint32_t val)
40 {
41     unsigned char buf[4];
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     write(buf, 4);
48 }
49
50 void OutputStream::write_u64(uint64_t val)
51 {
52     unsigned char buf[8];
53
54     buf[0] = val & 0xff;
55     buf[1] = (val >> 8) & 0xff;
56     buf[2] = (val >> 16) & 0xff;
57     buf[3] = (val >> 24) & 0xff;
58     buf[4] = (val >> 32) & 0xff;
59     buf[5] = (val >> 40) & 0xff;
60     buf[6] = (val >> 48) & 0xff;
61     buf[7] = (val >> 56) & 0xff;
62     write(buf, 8);
63 }
64
65 /* Writes an integer to an output stream using a variable-sized representation:
66  * seven bits are written at a time (little-endian), and the eigth bit of each
67  * byte is set if more data follows. */
68 void OutputStream::write_varint(uint64_t val)
69 {
70     do {
71         uint8_t remainder = (val & 0x7f);
72         val >>= 7;
73         if (val)
74             remainder |= 0x80;
75         write_u8(remainder);
76     } while (val);
77 }
78
79 /* Write an arbitrary string by first writing out the length, followed by the
80  * data itself. */
81 void OutputStream::write_string(const string &s)
82 {
83     size_t len = s.length();
84     write_varint(len);
85     write(s.data(), len);
86 }
87
88 void OutputStream::write_dictionary(const dictionary &d)
89 {
90     size_t size = d.size();
91     size_t written = 0;
92
93     write_varint(size);
94
95     for (dictionary::const_iterator i = d.begin(); i != d.end(); ++i) {
96         write_string(i->first);
97         write_string(i->second);
98         written++;
99     }
100
101     assert(written == size);
102 }
103
104 StringOutputStream::StringOutputStream()
105     : buf(std::ios_base::out)
106 {
107 }
108
109 void StringOutputStream::write_internal(const void *data, size_t len)
110 {
111     buf.write((const char *)data, len);
112     if (!buf.good())
113         throw IOException("error writing to StringOutputStream");
114 }
115
116 FileOutputStream::FileOutputStream(FILE *file)
117 {
118     f = file;
119 }
120
121 FileOutputStream::~FileOutputStream()
122 {
123     fclose(f);
124 }
125
126 void FileOutputStream::write_internal(const void *data, size_t len)
127 {
128     size_t res;
129
130     res = fwrite(data, 1, len, f);
131     if (res != len) {
132         throw IOException("write error");
133     }
134 }
135
136 /* Utility functions, for encoding data types to strings. */
137 string encode_u16(uint16_t val)
138 {
139     StringOutputStream s;
140     s.write_u16(val);
141     return s.contents();
142 }
143
144 string encode_u32(uint32_t val)
145 {
146     StringOutputStream s;
147     s.write_u32(val);
148     return s.contents();
149 }
150
151 string encode_u64(uint64_t val)
152 {
153     StringOutputStream s;
154     s.write_u64(val);
155     return s.contents();
156 }