CDFFDUseStruct::CDFFDUseStruct(CXmlTree::CElt *pp, signed char parent_type, CWnd* pParent /*=NULL*/) : CDialog(CDFFDUseStruct::IDD, pParent), saved_(pp->GetOwner()) { modified_ = false; first_ = false; // Default to first (see SetPosition()) pelt_ = pp; parent_type_ = parent_type; saved_.SaveKids(pelt_); saved_mod_flag_ = pelt_->GetOwner()->IsModified(); show_prev_next_ = !pParent->IsKindOf(RUNTIME_CLASS(CDataFormatView)) && (parent_type == CHexEditDoc::DF_FILE || parent_type == CHexEditDoc::DF_STRUCT || parent_type == CHexEditDoc::DF_DEFINE_STRUCT || parent_type == CHexEditDoc::DF_SWITCH || parent_type == CHexEditDoc::DF_UNION); pos_.x = pos_.y = -30000; pstruct_menu_ = new CMenu; pstruct_menu_->CreatePopupMenu(); // Build menu of structure definitions that the user can use // Note: define_struct elements are always the first children of the root (file) node CXmlTree::CElt ee = pelt_->GetOwner()->GetRoot().GetFirstChild(); int item_no; for (item_no = 1; !ee.IsEmpty() && ee.GetName() == "define_struct"; ++item_no, ++ee) pstruct_menu_->AppendMenu(MF_ENABLED, item_no, ee.GetAttr("type_name")); // Check if no items were added (no struct definitions found) if (item_no == 1) pstruct_menu_->AppendMenu(MF_GRAYED, -1, _T("No definitions available")); // Hook up the menu to the BCG button ctl_struct_var_.m_hMenu = pstruct_menu_->GetSafeHmenu(); ctl_struct_var_.m_bOSMenu = TRUE; ctl_struct_var_.m_bStayPressed = TRUE; ctl_struct_var_.m_bRightArrow = TRUE; //{{AFX_DATA_INIT(CDFFDUseStruct) comments_ = _T(""); name_ = _T(""); struct_ = _T(""); expr_ = _T(""); //}}AFX_DATA_INIT }
// Static functions used by make_var_menu_tree (below) static void add_menu_items(CMenu *pmenu, int &item_no, const CXmlTree::CElt ¤t_elt, CString name) { CString ss = current_elt.GetName(); // type of this node // Add element name unless parent is FOR (or we are IF/SWITCH/JUMP which use child name) if (ss != "if" && ss != "switch" && ss != "jump" && name.Right(1) != "]") name += current_elt.GetAttr("name"); if (ss == "data") { pmenu->AppendMenu(MF_ENABLED, item_no++, name); } else if (ss == "for") { // Add array access operator [] and add item(s) for sub-element ASSERT(current_elt.GetNumChildren() <= 1); // May be zero for new elt if (current_elt.GetNumChildren() > 0) add_menu_items(pmenu, item_no, current_elt.GetFirstChild(), name+"[ ]"); } else if (ss == "struct") { // Add items for all sub-elements of the struct for (CXmlTree::CElt ee = current_elt.GetFirstChild(); !ee.IsEmpty(); ++ee) { add_menu_items(pmenu, item_no, ee, name+"."); } } else if (ss == "use_struct") { CString ss = current_elt.GetAttr("type_name"); // Find struct name to use CXmlTree::CElt ee = current_elt.GetOwner()->GetRoot().GetFirstChild(); for ( ; !ee.IsEmpty() && ee.GetName() == "define_struct"; ++ee) if (ss == ee.GetAttr("type_name")) { // Check if recursive call to same defined struct for (std::vector<CString>::const_iterator ps = prev_defined.begin(); ps != prev_defined.end(); ++ps) { if (*ps == ss) return; // avoid recursion into same define_struct } prev_defined.push_back(ss); // Add items for all sub-elements of the struct for (CXmlTree::CElt ee2 = ee.GetFirstChild(); !ee2.IsEmpty(); ++ee2) { add_menu_items(pmenu, item_no, ee2, name+"."); } break; // Found the (hopefully) only one with the correct name } } else if (ss == "if") { if (current_elt.GetNumChildren() > 0) add_menu_items(pmenu, item_no, current_elt.GetFirstChild(), name); if (current_elt.GetNumChildren() > 1) { // Add a separate item for the else part ASSERT(current_elt.GetNumChildren() == 3 && current_elt.GetChild(1).GetName() == "else"); add_menu_items(pmenu, item_no, current_elt.GetChild(2), name); } } else if (ss == "switch") { // Add names of all case sub-elements CStringList found; // just used to eliminate duplicate data elts for (CXmlTree::CElt ee = current_elt.GetFirstChild(); !ee.IsEmpty(); ++ee) { ASSERT(ee.GetName() == "case"); if (ee.GetFirstChild().GetName() == "data") { CString ss = ee.GetFirstChild().GetAttr("name"); if (!ss.IsEmpty()) { if (found.Find(ss) != NULL) continue; // ignore data elements with the same name else found.AddTail(ss); // store this one for later checks } } add_menu_items(pmenu, item_no, ee.GetFirstChild(), name); } } else if (ss == "jump") { if (current_elt.GetNumChildren() > 0) add_menu_items(pmenu, item_no, current_elt.GetFirstChild(), name); } else if (ss == "define_struct" || ss == "eval") { // Do nothing here } else ASSERT(0); }
CString get_name(const CXmlTree::CElt &ee) { ASSERT(!ee.IsEmpty()); CString elt_type = ee.GetName(); if (elt_type == "define_struct") { return ee.GetAttr("type_name") + CString(" [STRUCT DEFN]"); } else if (elt_type == "struct") { return ee.GetAttr("name") + CString(" [STRUCT]"); } else if (elt_type == "use_struct") { return ee.GetAttr("name") + CString(" - using ") + ee.GetAttr("type_name"); } else if (elt_type == "for") { CString name = ee.GetAttr("name"); if (name.IsEmpty()) return CString("[FOR] - ") + get_name(ee.GetFirstChild()); else return name + CString(" [FOR]"); } else if (elt_type == "if") { CString name1 = get_name(ee.GetFirstChild()); CString name2; if (ee.GetNumChildren() > 1) { // Get name for else part ASSERT(ee.GetNumChildren() == 3 && ee.GetChild(1).GetName() == "else"); name2 = get_name(ee.GetChild(2)); } if (name1.IsEmpty()) name1 = name2; // no name for IF part so use else part else if (!name2.IsEmpty() && name1 != name2) name1 += "/" + name2; // Combine both names return CString("[IF] - ") + name1; } else if (elt_type == "switch") { return CString("[CASE] ") + ee.GetAttr("test"); } else if (elt_type == "jump") { return CString("[JUMP] - ") + get_name(ee.GetFirstChild()); } else if (elt_type == "eval") { return CString("[EVAL] ") + ee.GetAttr("expr"); } else if (elt_type == "data") { CString name = ee.GetAttr("name"); if (name.IsEmpty()) return CString("[DATA]"); else return name; } else ASSERT(0); return CString("ERROR"); }
// Return the size of an element (if it only contains data and/or struct elements) checking // the size of struct children if necessary. If any children are DATA elements with calc'd // size (or FOR or IF) then -1 is returned. long get_size(const CXmlTree::CElt &ee, int first /*=0*/, int last /*=999999999*/) { long retval = 0; CXmlTree::CElt child; int ii; int bits_used = 0; // Bits used by all consec. bitfields so far (0 if previous elt not a bitfield) int last_size; // Storage unit size of previous element if a bitfield (1,2,4, or 8) or 0 bool last_down; // Direction for previous bitfield (must be same dirn to be put in same stg unit) for (child = ee.GetChild(first), ii = first; !child.IsEmpty() && ii < last; ++child, ++ii) { CString elt_type = child.GetName(); if (elt_type != "data" && bits_used > 0) { // End of bit-field stg unit ASSERT(last_size == 1 || last_size == 2 || last_size == 4 || last_size == 8); retval += last_size; bits_used = 0; } if (elt_type == "data") { CString ss = child.GetAttr("type"); int data_bits = 0; // bits used in this element (or zero if not a bit-field) int data_size; bool data_down; // Check for bit-field (type is "int") if (ss.CompareNoCase("int") == 0) { data_bits = atoi(child.GetAttr("bits")); if (data_bits > 0) { data_size = atoi(child.GetAttr("len")); data_down = child.GetAttr("direction") == "down"; } } if (bits_used > 0 && (data_bits == 0 || // not bit-field data_size != last_size || // diff size data_down != last_down || // diff dirn bits_used + data_bits > data_size*8) // overflow stg unit ) { // Previous elt was end of the bit-field stg unit ASSERT(last_size == 1 || last_size == 2 || last_size == 4 || last_size == 8); retval += last_size; bits_used = 0; } if (data_bits > 0) { // Save info about current bit-field bits_used += data_bits; last_size = data_size; last_down = data_down; } else if (ss.CompareNoCase("char") == 0) { // Work out the size of a character (normally 1 unless Unicode) ss = child.GetAttr("format"); if (ss.CompareNoCase("unicode") == 0) retval += 2; else retval += 1; } else if (ss.CompareNoCase("date") == 0) { // Work out the size of the date field depending on the format ss = child.GetAttr("format"); if (ss.CompareNoCase("c") == 0) retval += 4; else if (ss.CompareNoCase("c51") == 0) retval += 4; else if (ss.CompareNoCase("c7") == 0) retval += 4; else if (ss.CompareNoCase("cmin") == 0) retval += 4; else if (ss.CompareNoCase("c64") == 0) retval += 8; else if (ss.CompareNoCase("ole") == 0) retval += 8; else if (ss.CompareNoCase("systemtime") == 0) retval += 16; else if (ss.CompareNoCase("filetime") == 0) retval += 8; else if (ss.CompareNoCase("msdos") == 0) retval += 4; else { ASSERT(0); return -1; } } else { // Get the size of the child by checking ss = child.GetAttr("len"); char *endp; //ss.TrimLeft(); //ss.TrimRight(); // Note: we could use expression parser to handle constant expression (eg, "10+1") but is it necessary? long len = strtoul(ss, &endp, 10); // Make sure the string was not empty and there was nothing after the number (eg, not "5+n") if (endp > (const char *)ss && endp - (const char *)ss == ss.GetLength()) retval +=len; else return -1L; // Does not appear to be a simple number so assume it is an expression } } else if (elt_type == "struct" || elt_type == "binary_file_format") { // Get the size of child by looking at its children long child_size = get_size(child); if (child_size > -1) retval += child_size; else return -1L; // Child size is indeterminate, therefore so is our size } else if (elt_type == "use_struct") { long tmp = -1; // Find define_struct and get its size CString ss = child.GetAttr("type_name"); // Find struct name to use CXmlTree::CElt ee = child.GetOwner()->GetRoot().GetFirstChild(); for ( ; !ee.IsEmpty() && ee.GetName() == "define_struct"; ++ee) if (ss == ee.GetAttr("type_name")) tmp = get_size(ee); // Not found if (tmp == -1) return -1L; else retval += tmp; } else if (elt_type == "eval" || elt_type == "jump" || elt_type == "define_struct") ; // zero size so just do nothing to retval else if (elt_type == "for") { // Get the size of the FOR elt's (only) child and multiply by the number of array elts long child_size = get_size(child); if (child_size <= -1) return -1L; // Child size is indeterminate, therefore so is our size // Handle FOR that contains a constant integer in count CString ss = child.GetAttr("count"); char *endp; ss.TrimLeft(); ss.TrimRight(); // Note: we could use expression parser to handle constant expression (eg, "10+1") but is it necessary? long count = strtoul(ss, &endp, 10); // Make sure the string was not empty and there was nothing after the number (eg not "10*n") if (endp > (const char *)ss && endp - (const char *)ss == ss.GetLength()) retval += count * child_size; else return -1L; // Does not appear to be a simple number so assume it is an expression } else return -1L; // xxx handle constant size IF/FOR } // Add last bit-field stg unit if there was one if (bits_used > 0) { ASSERT(last_size == 1 || last_size == 2 || last_size == 4 || last_size == 8); // Don't add stg unit if elt after the range (ie last) is part of the same unit as the previous elt bool add_last = true; if (last < ee.GetNumChildren()) // make sure we are not off the end { ASSERT(!child.IsEmpty()); int data_bits; // Check if last (elt one past the end) is part of the previous bit-field stg unit if (child.GetName() == "data" && // data field child.GetAttr("type").CompareNoCase("int") == 0 && // integer type (data_bits = atoi(child.GetAttr("bits"))) > 0 && // bitfield atoi(child.GetAttr("len")) == last_size && // same size as previous one (child.GetAttr("direction") == "down") == last_down && // same dirn as previous one bits_used + data_bits <= last_size*8) { add_last = false; // part way through a stg unit so don't add it to the size } } if (add_last) retval += last_size; } return retval; }