1
2 /* Web Polygraph http://www.web-polygraph.org/
3 * Copyright 2003-2011 The Measurement Factory
4 * Licensed under the Apache License, Version 2.0 */
5
6 #include "base/polygraph.h"
7
8 #include <ctype.h>
9
10 #include "xstd/h/sstream.h"
11 #include "xstd/Checksum.h"
12 #include "xstd/gadgets.h"
13 #include "base/AnyToString.h"
14 #include "base/BStream.h"
15 #include "runtime/IOBuf.h"
16
17 #include "csm/XmlTagParser.h"
18 #include "csm/oid2Url.h"
19 #include "csm/InjectIter.h"
20 #include "csm/EmbedContMdl.h"
21 #include "csm/ContentDbase.h"
22 #include "csm/cdbEntries.h"
23
24
25 /* CdbEntryPrnOpt */
26
CdbEntryPrnOpt()27 CdbEntryPrnOpt::CdbEntryPrnOpt(): buf(0), injector(0), sizeMax(-1),
28 entryOff(-1), entryData(0) {
29 }
30
31
32 /* CdbEntry */
33
Pour(const Area & image,bool divisible,CdbEntryPrnOpt & opt,bool & needMore)34 bool CdbEntry::Pour(const Area &image, bool divisible, CdbEntryPrnOpt &opt, bool &needMore) {
35 if (image.size() <= 0) { // empty
36 needMore = false;
37 opt.entryOff = 0;
38 return true;
39 }
40
41 if (!Should(opt.entryOff < image.size())) // internal error
42 return false;
43
44 Size remainingSize = Size(image.size()) - opt.entryOff;
45 if (remainingSize > opt.sizeMax) { // body ends sooner
46 if (!divisible)
47 return false; // and we cannot divide
48 remainingSize = opt.sizeMax;
49 }
50
51 const Size space = opt.buf->spaceSize();
52 if (remainingSize > space) {
53 needMore = true;
54 if (space > 0) {
55 opt.buf->append(image.data() + opt.entryOff, space);
56 opt.entryOff += space;
57 opt.sizeMax -= space;
58 }
59 } else {
60 needMore = false;
61 opt.buf->append(image.data() + opt.entryOff, remainingSize);
62 opt.entryOff = 0;
63 opt.sizeMax -= remainingSize;
64 }
65
66 return true;
67 }
68
69
70 /* CdbeBlob */
71
image(const String & anImage)72 void CdbeBlob::image(const String &anImage) {
73 theImage = anImage;
74 }
75
store(OBStream & ol) const76 OBStream &CdbeBlob::store(OBStream &ol) const {
77 return ol << theImage;
78 }
79
load(IBStream & il)80 IBStream &CdbeBlob::load(IBStream &il) {
81 return il >> theImage;
82 }
83
print(ostream & os) const84 ostream &CdbeBlob::print(ostream &os) const {
85 return os << theImage;
86 }
87
pour(CdbEntryPrnOpt & opt,bool & needMore) const88 bool CdbeBlob::pour(CdbEntryPrnOpt &opt, bool &needMore) const {
89 return Pour(theImage.area(0), false, opt, needMore);
90 }
91
92
93 /* CdbeText */
94
pour(CdbEntryPrnOpt & opt,bool & needMore) const95 bool CdbeText::pour(CdbEntryPrnOpt &opt, bool &needMore) const {
96 const Size mark = opt.buf->contSize();
97 if (!Pour(theImage.area(0), true, opt, needMore))
98 return false;
99 if (opt.injector)
100 opt.injector->inject(*opt.buf, 0, opt.buf->contSize() - mark);
101 return true;
102 }
103
104
105 /* CdbeLink */
106
size(CdbEntryPrnOpt & opt) const107 Size CdbeLink::size(CdbEntryPrnOpt &opt) const {
108 return generateImage(opt.embed).size();
109 }
110
meanSize() const111 Size CdbeLink::meanSize() const {
112 return Size(45); // roughly
113 }
114
store(OBStream & ol) const115 OBStream &CdbeLink::store(OBStream &ol) const {
116 return ol << contentCategory << origImage;
117 }
118
load(IBStream & il)119 IBStream &CdbeLink::load(IBStream &il) {
120 return il >> contentCategory >> origImage;
121 }
122
print(ostream & os) const123 ostream &CdbeLink::print(ostream &os) const {
124 return os << "[link:" << contentCategory << '@' << origImage << ']';
125 }
126
pour(CdbEntryPrnOpt & opt,bool & needMore) const127 bool CdbeLink::pour(CdbEntryPrnOpt &opt, bool &needMore) const {
128 CdbEntryPrnOpt::Embed &e = opt.embed;
129 if (!Should(e.model && e.rng))
130 return false;
131
132 const Area image = generateImage(e);
133 Should(image.size() > 0) &&
134 Should(*image.data() == '/');
135
136 if (!Pour(image, false, opt, needMore))
137 return false;
138
139 return true;
140 }
141
generateImage(CdbEntryPrnOpt::Embed & e) const142 Area CdbeLink::generateImage(CdbEntryPrnOpt::Embed &e) const {
143 Assert(e.model);
144
145 const ObjId eid =
146 e.model->embedCatOid(e.container, e.count, contentCategory);
147
148 static char buf[8*1024];
149 ofixedstream os(buf, sizeof(buf));
150 Oid2UrlPath(eid, os);
151 os.flush();
152 Should(os);
153
154 return Area::Create(buf, 0, Size(os.tellp()));
155 }
156
157
158 /* CdbePage */
159
CdbePage()160 CdbePage::CdbePage(): theDb(new ContentDbase) {
161 }
162
~CdbePage()163 CdbePage::~CdbePage() {
164 delete theDb;
165 }
166
size(CdbEntryPrnOpt & globOpt) const167 Size CdbePage::size(CdbEntryPrnOpt &globOpt) const {
168 CdbEntryPrnOpt opt = globOpt;
169 Size sum = 0;
170 int &pos = opt.embed.count;
171 for (pos = 0; pos < theDb->count(); ++pos) {
172 const CdbEntry *e = theDb->entry(pos);
173 sum += e->size(opt);
174 }
175 return sum;
176 }
177
meanSize() const178 Size CdbePage::meanSize() const {
179 return int(theDb->entrySizeMean() * theDb->count());
180 }
181
add(CdbEntry * e)182 void CdbePage::add(CdbEntry *e) {
183 theDb->add(e);
184 }
185
store(OBStream & ol) const186 OBStream &CdbePage::store(OBStream &ol) const {
187 theDb->store(ol);
188 return ol;
189 }
190
load(IBStream & il)191 IBStream &CdbePage::load(IBStream &il) {
192 theDb->load(il);
193 return il;
194 }
195
print(ostream & os) const196 ostream &CdbePage::print(ostream &os) const {
197 return theDb->print(os);
198 }
199
200 // based on CdbBodyIter::pourMiddle
pour(CdbEntryPrnOpt & globOpt,bool & needMore) const201 bool CdbePage::pour(CdbEntryPrnOpt &globOpt, bool &needMore) const {
202 CdbEntryPrnOpt &opt = globOpt;
203
204 for (int &pos = opt.entryData; pos < theDb->count() && opt.sizeMax > 0; ++pos) {
205 const CdbEntry *e = theDb->entry(pos);
206 opt.embed.count = pos;
207
208 if (!e->pour(opt, needMore))
209 return false; // current entry will never fit
210
211 if (needMore)
212 return true;
213 }
214
215 needMore = false;
216 return true;
217 }
218