Пример #1
0
// Static functions used by make_var_menu_tree (below)
static void add_menu_items(CMenu *pmenu, int &item_no, const CXmlTree::CElt &current_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);
}
Пример #2
0
// 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;
}