vfs: check userland buffers before reading them.
[haiku.git] / src / libs / alm / SharedSolver.cpp
blob10a83d0a04b8bdb834c5cb81e0b71363f6e6a2f4
1 /*
2 * Copyright 2012, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "SharedSolver.h"
9 #include <set>
11 #include <ALMLayout.h>
12 #include <AutoDeleter.h>
13 #include <ObjectList.h>
15 #include "RowColumnManager.h"
18 using LinearProgramming::LinearSpec;
21 namespace {
23 type_code kConstraintsTypeCode = 'cnst';
24 const char* kConstraintsField = "SharedSolver:constraints";
29 struct SharedSolver::MinSizeValidator {
30 inline void CallSolverMethod(LinearSpec* spec, VariableList* vars)
32 spec->FindMins(vars);
35 inline void Finalize(BALMLayout* layout, SharedSolver* solver,
36 ResultType solveResult)
38 if (solveResult == LinearProgramming::kUnbounded) {
39 solver->SetMinSize(layout, BSize(0, 0));
40 } else {
41 solver->SetMinSize(layout, BSize(ceilf(layout->Right()->Value()),
42 ceilf(layout->Bottom()->Value())));
48 struct SharedSolver::MaxSizeValidator {
49 inline void CallSolverMethod(LinearSpec* spec, VariableList* vars)
51 spec->FindMaxs(vars);
54 inline void Finalize(BALMLayout* layout, SharedSolver* solver,
55 ResultType solveResult)
57 if (solveResult == LinearProgramming::kUnbounded) {
58 solver->SetMaxSize(layout,
59 BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED));
60 } else {
61 solver->SetMaxSize(layout, BSize(floorf(layout->Right()->Value()),
62 floorf(layout->Bottom()->Value())));
68 struct SharedSolver::PreferredSizeValidator {
69 inline void CallSolverMethod(LinearSpec* spec, VariableList* vars)
71 spec->Solve();
74 inline void Finalize(BALMLayout* layout, SharedSolver* solver,
75 ResultType solveResult)
77 float width = layout->Right()->Value() - layout->Left()->Value();
78 float height = layout->Bottom()->Value() - layout->Top()->Value();
79 solver->SetPreferredSize(layout, BSize(width, height));
84 SharedSolver::SharedSolver()
86 fConstraintsValid(false),
87 fMinValid(false),
88 fMaxValid(false),
89 fPreferredValid(false),
90 fLayoutValid(false),
91 fLayoutContext(NULL)
96 SharedSolver::SharedSolver(BMessage* archive)
98 BArchivable(archive),
99 fConstraintsValid(false),
100 fMinValid(false),
101 fMaxValid(false),
102 fPreferredValid(false),
103 fLayoutValid(false),
104 fLayoutContext(NULL)
109 SharedSolver::~SharedSolver()
111 if (fLayouts.CountItems() > 0)
112 debugger("SharedSolver deleted while still in use!");
114 _SetContext(NULL);
118 LinearSpec*
119 SharedSolver::Solver() const
121 return const_cast<LinearSpec*>(&fLinearSpec);
125 void
126 SharedSolver::Invalidate(bool children)
128 if (!fConstraintsValid && !fMaxValid && !fMinValid && !fLayoutValid)
129 return;
131 fConstraintsValid = false;
132 fMinValid = false;
133 fMaxValid = false;
134 fPreferredValid = false;
135 fLayoutValid = false;
137 _SetContext(NULL);
139 for (int32 i = fLayouts.CountItems() - 1; i >= 0; i--)
140 fLayouts.ItemAt(i)->InvalidateLayout(children);
144 void
145 SharedSolver::RegisterLayout(BALMLayout* layout)
147 fLayouts.AddItem(layout);
148 Invalidate(false);
152 void
153 SharedSolver::LayoutLeaving(const BALMLayout* layout)
155 fLayouts.RemoveItem(const_cast<BALMLayout*>(layout));
156 Invalidate(false);
160 ResultType
161 SharedSolver::ValidateMinSize()
163 _Validate<MinSizeValidator>(fMinValid, fMinResult);
164 return fMinResult;
168 ResultType
169 SharedSolver::ValidateMaxSize()
171 _Validate<MaxSizeValidator>(fMaxValid, fMaxResult);
172 return fMaxResult;
176 ResultType
177 SharedSolver::ValidatePreferredSize()
179 _Validate<PreferredSizeValidator>(fPreferredValid, fPreferredResult);
180 return fPreferredResult;
184 ResultType
185 SharedSolver::ValidateLayout(BLayoutContext* context)
187 if (fLayoutValid && fLayoutContext == context)
188 return fLayoutResult;
190 _SetContext(context);
191 _ValidateConstraints();
193 for (int32 i = fLayouts.CountItems() - 1; i >= 0; i--) {
194 BALMLayout* layout = fLayouts.ItemAt(i);
195 BSize size(layout->LayoutArea().Size());
196 layout->Right()->SetRange(size.width, size.width);
197 layout->Bottom()->SetRange(size.height, size.height);
200 fLayoutResult = fLinearSpec.Solve();
201 fLayoutValid = true;
202 return fLayoutResult;
206 status_t
207 SharedSolver::Archive(BMessage* archive, bool deep) const
209 return BArchivable::Archive(archive, deep);
213 status_t
214 SharedSolver::AllArchived(BMessage* archive) const
217 for each archived layout:
218 add it to our archive
219 add constraints created by areas and column manager to a set
220 add range constraints on the left/top/right/bottom tabs to the same set
221 for each constraint in the linear spec:
222 if it is not in the set above:
223 archive it
225 BArchiver archiver(archive);
226 std::set<const Constraint*> autoConstraints;
227 for (int32 i = fLayouts.CountItems() - 1; i >= 0; i--) {
228 BALMLayout* layout = fLayouts.ItemAt(i);
229 if (!archiver.IsArchived(layout))
230 continue;
232 for (int32 j = layout->CountItems() - 1; j >= 0; j--)
233 _AddConstraintsToSet(layout->AreaAt(j), autoConstraints);
235 for (int32 j = layout->fRowColumnManager->fRows.CountItems() - 1;
236 j >= 0; j--) {
237 Row* row = layout->fRowColumnManager->fRows.ItemAt(j);
238 autoConstraints.insert(row->fPrefSizeConstraint);
241 for (int32 j = layout->fRowColumnManager->fColumns.CountItems() - 1;
242 j >= 0; j--) {
243 Column* column = layout->fRowColumnManager->fColumns.ItemAt(j);
244 autoConstraints.insert(column->fPrefSizeConstraint);
247 Variable* corners[] = {layout->fLeft, layout->fTop, layout->fRight,
248 layout->fBottom};
250 for (int32 j = 0; j < 4; j++) {
251 const Constraint* min;
252 const Constraint* max;
253 fLinearSpec.GetRangeConstraints(corners[j], &min, &max);
254 if (min)
255 autoConstraints.insert(min);
256 if (max)
257 autoConstraints.insert(max);
261 status_t err = B_OK;
262 const ConstraintList& constraints = fLinearSpec.Constraints();
263 for (int32 i = constraints.CountItems() - 1; i >= 0 && err == B_OK; i--) {
264 Constraint* constraint = constraints.ItemAt(i);
265 if (autoConstraints.find(constraint) == autoConstraints.end())
266 err = _AddConstraintToArchive(constraint, archive);
268 return err;
272 status_t
273 SharedSolver::AllUnarchived(const BMessage* archive)
275 int32 count = 0;
276 archive->GetInfo(kConstraintsField, NULL, &count);
278 status_t err = B_OK;
279 BUnarchiver unarchiver(archive);
280 for (int32 i = 0; i < count && err == B_OK; i++) {
281 const void* constraintData;
282 ssize_t numBytes;
283 err = archive->FindData(kConstraintsField, kConstraintsTypeCode,
284 i, &constraintData, &numBytes);
285 if (err != B_OK)
286 return err;
288 err = _InstantiateConstraint(constraintData, numBytes, unarchiver);
290 return err;
294 void
295 SharedSolver::_AddConstraintsToSet(Area* area,
296 std::set<const Constraint*>& constraints)
298 if (area->fMinContentWidth)
299 constraints.insert(area->fMinContentWidth);
300 if (area->fMaxContentWidth)
301 constraints.insert(area->fMaxContentWidth);
302 if (area->fMinContentHeight)
303 constraints.insert(area->fMinContentHeight);
304 if (area->fMaxContentHeight)
305 constraints.insert(area->fMaxContentHeight);
306 if (area->fContentAspectRatioC)
307 constraints.insert(area->fContentAspectRatioC);
311 status_t
312 SharedSolver::_AddConstraintToArchive(Constraint* constraint,
313 BMessage* archive)
315 /* Format:
316 * int32: summandCount
317 * { int32 : token
318 * double: coefficient
319 * } [summandCount]
320 * int32: operator
321 * double: rightSide
322 * double: penaltyNeg
323 * double: penaltyPos
326 // TODO: check Read/Write calls
327 BArchiver archiver(archive);
328 BMallocIO buffer;
329 SummandList* leftSide = constraint->LeftSide();
330 int32 summandCount = leftSide->CountItems();
331 buffer.Write(&summandCount, sizeof(summandCount));
333 for (int32 i = 0; i < summandCount; i++) {
334 Summand* summand = leftSide->ItemAt(i);
335 Variable* var = summand->Var();
336 BArchivable* varArchivable = dynamic_cast<BArchivable*>(var);
337 if (!varArchivable || !archiver.IsArchived(varArchivable))
338 return B_NAME_NOT_FOUND;
340 int32 token;
341 archiver.GetTokenForArchivable(varArchivable, token);
342 buffer.Write(&token, sizeof(token));
344 double coefficient = summand->Coeff();
345 buffer.Write(&coefficient, sizeof(coefficient));
348 int32 op = constraint->Op();
349 buffer.Write(&op, sizeof(op));
351 double rightSide = constraint->RightSide();
352 buffer.Write(&rightSide, sizeof(rightSide));
353 double penaltyNeg = constraint->PenaltyNeg();
354 buffer.Write(&penaltyNeg, sizeof(penaltyNeg));
355 double penaltyPos = constraint->PenaltyPos();
356 buffer.Write(&penaltyPos, sizeof(penaltyPos));
358 return archive->AddData(kConstraintsField, kConstraintsTypeCode,
359 buffer.Buffer(), buffer.BufferLength(), false);
363 status_t
364 SharedSolver::_InstantiateConstraint(const void* rawData, ssize_t numBytes,
365 BUnarchiver& unarchiver)
367 /* Format:
368 * int32: summandCount
369 * { int32 : token
370 * double: coefficient
371 * } [summandCount]
372 * int32: operator
373 * double: rightSide
374 * double: penaltyNeg
375 * double: penaltyPos
378 // TODO: check Read/Write calls
379 BMemoryIO buffer(rawData, numBytes);
380 int32 summandCount;
381 buffer.Read((void*)&summandCount, sizeof(summandCount));
383 SummandList* summandList = new SummandList(20, true);
384 ObjectDeleter<SummandList> deleter(summandList);
385 status_t err = B_OK;
386 for (int32 i = 0; i < summandCount; i++) {
387 int32 token;
388 buffer.Read((void*)&token, sizeof(token));
390 BArchivable* varArchivable;
391 err = unarchiver.GetObject(token, varArchivable);
392 if (err != B_OK)
393 break;
394 Variable* var = dynamic_cast<Variable*>(varArchivable);
395 if (!var)
396 return B_BAD_TYPE;
398 fLinearSpec.AddVariable(var);
400 double coefficient;
401 buffer.Read(&coefficient, sizeof(coefficient));
403 summandList->AddItem(new Summand(coefficient, var));
406 int32 op;
407 buffer.Read(&op, sizeof(op));
409 double rightSide;
410 buffer.Read(&rightSide, sizeof(rightSide));
411 double penaltyNeg;
412 buffer.Read(&penaltyNeg, sizeof(penaltyNeg));
413 double penaltyPos;
414 buffer.Read(&penaltyPos, sizeof(penaltyPos));
416 if (err != B_OK)
417 return err;
419 if (fLinearSpec.AddConstraint(summandList, (OperatorType)op, rightSide,
420 penaltyNeg, penaltyPos) != NULL) {
421 deleter.Detach();
422 return B_OK;
425 return B_NO_MEMORY;
429 void
430 SharedSolver::SetMaxSize(BALMLayout* layout, const BSize& max)
432 layout->fMaxSize = max;
436 void
437 SharedSolver::SetMinSize(BALMLayout* layout, const BSize& min)
439 layout->fMinSize = min;
443 void
444 SharedSolver::SetPreferredSize(BALMLayout* layout, const BSize& preferred)
446 layout->fPreferredSize = preferred;
450 void
451 SharedSolver::LayoutContextLeft(BLayoutContext* context)
453 fLayoutContext = NULL;
457 void
458 SharedSolver::_SetContext(BLayoutContext* context)
460 if (fLayoutContext)
461 fLayoutContext->RemoveListener(this);
462 fLayoutContext = context;
463 if (fLayoutContext)
464 fLayoutContext->AddListener(this);
468 void
469 SharedSolver::_ValidateConstraints()
471 if (!fConstraintsValid) {
472 for (int32 i = fLayouts.CountItems() - 1; i >= 0; i--) {
473 fLayouts.ItemAt(i)->UpdateConstraints(fLayoutContext);
475 fConstraintsValid = true;
480 template <class Validator>
481 void
482 SharedSolver::_Validate(bool& isValid, ResultType& result)
484 if (isValid)
485 return;
487 _ValidateConstraints();
489 VariableList variables(fLayouts.CountItems() * 2);
490 Validator validator;
492 for (int32 i = fLayouts.CountItems() - 1; i >= 0; i--) {
493 BALMLayout* layout = fLayouts.ItemAt(i);
494 layout->Right()->SetRange(0, 20000);
495 layout->Bottom()->SetRange(0, 20000);
497 variables.AddItem(layout->Right());
498 variables.AddItem(layout->Bottom());
501 validator.CallSolverMethod(&fLinearSpec, &variables);
502 result = fLinearSpec.Result();
504 for (int32 i = fLayouts.CountItems() - 1; i >= 0; i--)
505 validator.Finalize(fLayouts.ItemAt(i), this, result);
507 isValid = true;
508 fLayoutValid = false;
512 BArchivable*
513 SharedSolver::Instantiate(BMessage* archive)
515 if (validate_instantiation(archive, "BPrivate::SharedSolver"))
516 return new SharedSolver(archive);
517 return NULL;