C4FindObject *C4FindObject::CreateByValue(const C4Value &DataVal, C4SortObject **ppSortObj) { // Must be an array C4ValueArray *pArray = C4Value(DataVal).getArray(); if (!pArray) return NULL; const C4ValueArray &Data = *pArray; int32_t iType = Data[0].getInt(); if (Inside<int32_t>(iType, C4SO_First, C4SO_Last)) { // this is not a FindObject but a sort condition! // sort condition not desired here? if (!ppSortObj) return NULL; // otherwise, create it! *ppSortObj = C4SortObject::CreateByValue(iType, Data); // done return NULL; } switch (iType) { case C4FO_Not: { // Create child condition C4FindObject *pCond = C4FindObject::CreateByValue(Data[1]); if (!pCond) return NULL; // wrap return new C4FindObjectNot(pCond); } case C4FO_And: case C4FO_Or: { // Trivial case (one condition) if (Data.GetSize() == 2) return C4FindObject::CreateByValue(Data[1]); // Create all childs int32_t i; C4FindObject **ppConds = new C4FindObject *[Data.GetSize() - 1]; for (i = 0; i < Data.GetSize() - 1; i++) ppConds[i] = C4FindObject::CreateByValue(Data[i + 1]); // Count real entries, move them to start of list int32_t iSize = 0; for (i = 0; i < Data.GetSize() - 1; i++) if (ppConds[i]) if (iSize++ != i) ppConds[iSize - 1] = ppConds[i]; // Create if (iType == C4FO_And) return new C4FindObjectAnd(iSize, ppConds); else return new C4FindObjectOr(iSize, ppConds); } case C4FO_Exclude: return new C4FindObjectExclude(Data[1].getObj()); case C4FO_ID: return new C4FindObjectID(Data[1].getC4ID()); case C4FO_InRect: return new C4FindObjectInRect(C4Rect(Data[1].getInt(), Data[2].getInt(), Data[3].getInt(), Data[4].getInt())); case C4FO_AtPoint: return new C4FindObjectAtPoint(Data[1].getInt(), Data[2].getInt()); case C4FO_AtRect: return new C4FindObjectAtRect(Data[1].getInt(), Data[2].getInt(), Data[3].getInt(), Data[4].getInt()); case C4FO_OnLine: return new C4FindObjectOnLine(Data[1].getInt(), Data[2].getInt(), Data[3].getInt(), Data[4].getInt()); case C4FO_Distance: return new C4FindObjectDistance(Data[1].getInt(), Data[2].getInt(), Data[3].getInt()); case C4FO_OCF: return new C4FindObjectOCF(Data[1].getInt()); case C4FO_Category: return new C4FindObjectCategory(Data[1].getInt()); case C4FO_Action: { C4String *pStr = Data[1].getStr(); if (!pStr) return NULL; // Don't copy, it should be safe return new C4FindObjectAction(pStr->Data.getData()); } case C4FO_Func: { // Get function name C4String *pStr = Data[1].getStr(); if (!pStr) return NULL; // Construct C4FindObjectFunc *pFO = new C4FindObjectFunc(pStr->Data.getData()); // Add parameters for (int i = 2; i < Data.GetSize(); i++) pFO->SetPar(i - 2, Data[i]); // Done return pFO; } case C4FO_ActionTarget: { int index = 0; if (Data.GetSize() >= 3) index = BoundBy(Data[2].getInt(), 0, 1); return new C4FindObjectActionTarget(Data[1].getObj(), index); } case C4FO_Container: return new C4FindObjectContainer(Data[1].getObj()); case C4FO_AnyContainer: return new C4FindObjectAnyContainer(); case C4FO_Owner: return new C4FindObjectOwner(Data[1].getInt()); case C4FO_Controller: return new C4FindObjectController(Data[1].getInt()); case C4FO_Layer: return new C4FindObjectLayer(Data[1].getObj()); } return NULL; }
C4FindObject *C4FindObject::CreateByValue(const C4Value &DataVal, C4SortObject **ppSortObj, const C4Object *context, bool *has_layer_check) { // Must be an array C4ValueArray *pArray = C4Value(DataVal).getArray(); if (!pArray) return NULL; const C4ValueArray &Data = *pArray; int32_t iType = Data[0].getInt(); if (Inside<int32_t>(iType, C4SO_First, C4SO_Last)) { // this is not a FindObject but a sort condition! // sort condition not desired here? if (!ppSortObj) return NULL; // otherwise, create it! *ppSortObj = C4SortObject::CreateByValue(iType, Data, context); // done return NULL; } switch (iType) { case C4FO_Not: { // Create child condition C4FindObject *pCond = C4FindObject::CreateByValue(Data[1], nullptr, context, has_layer_check); if (!pCond) return NULL; // wrap return new C4FindObjectNot(pCond); } case C4FO_And: case C4FO_Or: { // Trivial case (one condition) if (Data.GetSize() == 2) return C4FindObject::CreateByValue(Data[1], nullptr, context, has_layer_check); // Create all childs int32_t i; C4FindObject **ppConds = new C4FindObject *[Data.GetSize() - 1]; for (i = 0; i < Data.GetSize() - 1; i++) ppConds[i] = C4FindObject::CreateByValue(Data[i + 1], nullptr, context, has_layer_check); // Count real entries, move them to start of list int32_t iSize = 0; for (i = 0; i < Data.GetSize() - 1; i++) if (ppConds[i]) if (iSize++ != i) ppConds[iSize-1] = ppConds[i]; // Create if (iType == C4FO_And) return new C4FindObjectAnd(iSize, ppConds); else return new C4FindObjectOr(iSize, ppConds); } case C4FO_Exclude: return new C4FindObjectExclude(Data[1].getObj()); case C4FO_ID: return new C4FindObjectDef(Data[1].getPropList()); // #973: For all criteria using coordinates: If FindObject et al. are called in object context, offset by object center case C4FO_InRect: { int32_t x = Data[1].getInt(); int32_t y = Data[2].getInt(); int32_t w = Data[3].getInt(); int32_t h = Data[4].getInt(); if (context) { x += context->GetX(); y += context->GetY(); } return new C4FindObjectInRect(C4Rect(x, y, w, h)); } case C4FO_AtPoint: { int32_t x = Data[1].getInt(); int32_t y = Data[2].getInt(); if (context) { x += context->GetX(); y += context->GetY(); } return new C4FindObjectAtPoint(x, y); } case C4FO_AtRect: { int32_t x = Data[1].getInt(); int32_t y = Data[2].getInt(); int32_t w = Data[3].getInt(); int32_t h = Data[4].getInt(); if (context) { x += context->GetX(); y += context->GetY(); } return new C4FindObjectAtRect(x, y, w, h); } case C4FO_OnLine: { int32_t x1 = Data[1].getInt(); int32_t y1 = Data[2].getInt(); int32_t x2 = Data[3].getInt(); int32_t y2 = Data[4].getInt(); if (context) { x1 += context->GetX(); x2 += context->GetX(); y1 += context->GetY(); y2 += context->GetY(); } return new C4FindObjectOnLine(x1, y1, x2, y2); } case C4FO_Distance: { int32_t x = Data[1].getInt(); int32_t y = Data[2].getInt(); if (context) { x += context->GetX(); y += context->GetY(); } return new C4FindObjectDistance(x, y, Data[3].getInt()); } case C4FO_OCF: return new C4FindObjectOCF(Data[1].getInt()); case C4FO_Category: return new C4FindObjectCategory(Data[1].getInt()); case C4FO_Action: { C4String *pStr = Data[1].getStr(); if (!pStr) return NULL; // Don't copy, it should be safe return new C4FindObjectAction(pStr->GetCStr()); } case C4FO_Func: { // Get function name C4String *pStr = Data[1].getStr(); if (!pStr) return NULL; // Construct C4FindObjectFunc *pFO = new C4FindObjectFunc(pStr); // Add parameters for (int i = 2; i < Data.GetSize(); i++) pFO->SetPar(i - 2, Data[i]); // Done return pFO; } case C4FO_ActionTarget: { int index = 0; if (Data.GetSize() >= 3) index = Clamp(Data[2].getInt(), 0, 1); return new C4FindObjectActionTarget(Data[1].getObj(), index); } case C4FO_Procedure: return new C4FindObjectProcedure(Data[1].getStr()); case C4FO_Container: return new C4FindObjectContainer(Data[1].getObj()); case C4FO_AnyContainer: return new C4FindObjectAnyContainer(); case C4FO_Owner: return new C4FindObjectOwner(Data[1].getInt()); case C4FO_Controller: return new C4FindObjectController(Data[1].getInt()); case C4FO_Layer: // explicit layer check given. do not add implicit layer check if (has_layer_check) *has_layer_check = true; return new C4FindObjectLayer(Data[1].getObj()); case C4FO_InArray: return new C4FindObjectInArray(Data[1].getArray()); case C4FO_Property: { // Get property name C4String *pStr = Data[1].getStr(); if (!pStr) return NULL; // Construct C4FindObjectProperty *pFO = new C4FindObjectProperty(pStr); // Done return pFO; } case C4FO_AnyLayer: // do not add implicit layer check if (has_layer_check) *has_layer_check = true; return NULL; } return NULL; }