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