-
Notifications
You must be signed in to change notification settings - Fork 5
/
file_io.cc
197 lines (184 loc) · 5.99 KB
/
file_io.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
// Copyright...
#include "file_io.h"
#include <memory>
#include <podofo/doc/PdfFileSpec.h>
#include <podofo/doc/PdfMemDocument.h>
#include <poppler/cpp/poppler-document.h>
#include <poppler/cpp/poppler-embedded-file.h>
#include "document.pb.h"
#include "document_view.h"
#include "graphic_factory.h"
using std::make_shared;
using std::string;
using std::unique_ptr;
using std::vector;
// File format. Keep this synced with the code.
//
// All integers are big endian.
//
// char[4] magic: 'skch'
// uint32 version: 1
// uint32 num_pdfs: Number of PDFs embedded. Must be 1 for now.
// uint64 pdf_len: Number of bytes in PDF
// char[pdf_len] pdf: PDF Data
// uint64 overlay_len: Length of overlay protobuf
// char[overlay_len] overlays: Overlays protobuf data
namespace pdfsketch {
namespace {
const char kMagic[] = {'s', 'k', 'c', 'h'};
uint32_t DecodeUInt32(const unsigned char* buf) {
return
(static_cast<uint32_t>(buf[0]) << (8 * 3)) |
(static_cast<uint32_t>(buf[1]) << (8 * 2)) |
(static_cast<uint32_t>(buf[2]) << (8 * 1)) |
(static_cast<uint32_t>(buf[3]) << (8 * 0));
}
uint64_t DecodeUInt64(const unsigned char* buf) {
return
(static_cast<uint64_t>(buf[0]) << (8 * 7)) |
(static_cast<uint64_t>(buf[1]) << (8 * 6)) |
(static_cast<uint64_t>(buf[2]) << (8 * 5)) |
(static_cast<uint64_t>(buf[3]) << (8 * 4)) |
(static_cast<uint64_t>(buf[4]) << (8 * 3)) |
(static_cast<uint64_t>(buf[5]) << (8 * 2)) |
(static_cast<uint64_t>(buf[6]) << (8 * 1)) |
(static_cast<uint64_t>(buf[7]) << (8 * 0));
}
void EncodeUInt32(uint32_t num, char* out) {
out[0] = (num >> (8 * 3)) & 0xff;
out[1] = (num >> (8 * 2)) & 0xff;
out[2] = (num >> (8 * 1)) & 0xff;
out[3] = (num >> (8 * 0)) & 0xff;
}
void EncodeUInt64(uint64_t num, char* out) {
out[0] = (num >> (8 * 7)) & 0xff;
out[1] = (num >> (8 * 6)) & 0xff;
out[2] = (num >> (8 * 5)) & 0xff;
out[3] = (num >> (8 * 4)) & 0xff;
out[4] = (num >> (8 * 3)) & 0xff;
out[5] = (num >> (8 * 2)) & 0xff;
out[6] = (num >> (8 * 1)) & 0xff;
out[7] = (num >> (8 * 0)) & 0xff;
}
void PushUInt32(uint32_t num, vector<char>* out) {
char buf[4];
EncodeUInt32(num, buf);
out->insert(out->end(), buf, buf + sizeof(buf));
}
void PushUInt64(uint32_t num, vector<char>* out) {
char buf[8];
EncodeUInt64(num, buf);
out->insert(out->end(), buf, buf + sizeof(buf));
}
// Returns buf advanced past the parsed item
const char* ParseUInt32(const char* buf, uint32_t* out) {
*out = DecodeUInt32(reinterpret_cast<const unsigned char*>(buf));
return buf + 4;
}
const char* ParseUInt64(const char* buf, uint64_t* out) {
*out = DecodeUInt64(reinterpret_cast<const unsigned char*>(buf));
return buf + 8;
}
} // namespace {}
void FileIO::OpenPDF(const char* doc, size_t doc_len,
DocumentView* document_view) {
const char kMagic[] = {'s', 'k', 'c', 'h'};
if (doc_len < sizeof(kMagic))
return;
if (!strncmp(doc, kMagic, sizeof(kMagic))) {
printf("loading saved file\n");
OpenSkch(doc, doc_len, document_view);
} else {
// Loading PDF. Check for embedded save file
unique_ptr<poppler::document> poppler_doc(
poppler::document::load_from_raw_data(doc, doc_len));
if (!poppler_doc.get()) {
printf("can't make poppler doc from data\n");
return;
}
if (poppler_doc->has_embedded_files()) {
for (auto file : poppler_doc->embedded_files()) {
if (file->is_valid() &&
file->name() == "source.pdfsketch" &&
file->size() > sizeof(kMagic)) {
printf("loading embedded save file\n");
vector<char> data = file->data();
OpenSkch(&data[0], data.size(), document_view);
return;
}
}
}
printf("no save file found. making new doc\n");
document_view->LoadFromPDF(doc, doc_len);
}
}
void FileIO::OpenSkch(const char* buf, size_t len,
DocumentView* doc) {
size_t start = (size_t)buf;
if (strncmp(buf, kMagic, sizeof(kMagic))) {
printf("%s: Missing magic\n", __func__);
return;
}
buf += sizeof(kMagic);
printf("now at (after magic) %zu\n", ((size_t)buf) - start);
uint32_t version = 0;
buf = ParseUInt32(buf, &version);
printf("now at (after version parse) %zu\n", ((size_t)buf) - start);
if (version != 1) {
printf("%s: Invalid version\n", __func__);
return;
}
uint32_t num_pdfs = 0;
printf("parsing at offset %zu: %d %d %d %d\n", ((size_t)buf) - start,
buf[0], buf[1], buf[2], buf[3]);
buf = ParseUInt32(buf, &num_pdfs);
if (num_pdfs != 1) {
printf("%s: Invalid PDF count: %d\n", __func__, num_pdfs);
return;
}
uint64_t pdfdata_len = 0;
buf = ParseUInt64(buf, &pdfdata_len);
if (pdfdata_len > len) {
// sanity check
printf("%s: PDF too big\n", __func__);
return;
}
const char* pdf_doc = buf;
buf += pdfdata_len;
uint64_t overlay_len = 0;
buf = ParseUInt64(buf, &overlay_len);
if (overlay_len > len) {
// sanity check
printf("%s: overlays too big\n", __func__);
return;
}
pdfsketchproto::Document msg;
if (!msg.ParseFromArray(buf, overlay_len)) {
printf("protobuf decode failed\n");
return;
}
doc->LoadFromPDF(pdf_doc, pdfdata_len);
for (int i = 0; i < msg.graphic_size(); i++) {
const pdfsketchproto::Graphic& gr = msg.graphic(i);
doc->AddGraphic(GraphicFactory::NewGraphic(gr));
}
}
void FileIO::Save(const DocumentView& doc, std::vector<char>* out) {
out->insert(out->end(), kMagic, kMagic + sizeof(kMagic));
PushUInt32(1, out); // version
PushUInt32(1, out); // number of pdfs
const char* pdfdata = NULL;
size_t pdfdata_len = 0;
doc.GetPDFData(&pdfdata, &pdfdata_len);
PushUInt64(pdfdata_len, out);
out->insert(out->end(), pdfdata, pdfdata + pdfdata_len); // pdf data
pdfsketchproto::Document msg;
doc.Serialize(&msg);
string msg_buf;
if (!msg.SerializeToString(&msg_buf)) {
printf("error serializing to string\n");
}
PushUInt64(msg_buf.size(), out);
out->insert(out->end(), msg_buf.begin(), msg_buf.end());
}
} // namespace pdfsketch