Click here to Skip to main content
15,867,956 members
Please Sign up or sign in to vote.
5.00/5 (3 votes)
See more:
Hi, I want to parse MP4 files and am just starting on the code for it. I think that I will need an enum of all the "box types" that can appear in a file so I would like to create something like this:

C#
protected enum boxType : uint
{
    ftyp = 0x66747970,
    pdin = 0x6e696470,
    moov = 0x6d6f6f76
    ...
}


This, however, is very ugly in my eyes so I am asking: Is there a construct that could convert specially constricted strings to uints in a static context?

This might explain what I want:

C#
protected enum boxType : uint
{
    ftyp = BitConverter.ToUInt32(Encoding.ASCII.GetBytes("ftyp"), 0),
    pdin = BitConverter.ToUInt32(Encoding.ASCII.GetBytes("pdin"), 0),
    moov = BitConverter.ToUInt32(Encoding.ASCII.GetBytes("moov"), 0),
    ...
}


These are not considered to be constant expressions so they can't be used in the declaration of an enum like this, but is there something else one can do to get the intended result?
Posted
Comments
Sergey Alexandrovich Kryukov 26-Dec-13 22:15pm    
Interesting question. My 5. I do have a solution. Just wait a bit.
—SA

C#
protected struct boxType
{
    public static uint ftyp = BitConverter.ToUInt32(Encoding.ASCII.GetBytes("ftyp"), 0);
    public static uint pdin = BitConverter.ToUInt32(Encoding.ASCII.GetBytes("pdin"), 0);
    public static uint moov = BitConverter.ToUInt32(Encoding.ASCII.GetBytes("moov"), 0);
}
You must make the static Fields 'public to get IntelliSense.

But, is this beauty ? :)
 
Share this answer
 
Comments
Ron Beyer 26-Dec-13 16:20pm    
+5 for realizing that in this case, Enum is nothing more than a convenient container for constants, which is just as useful as putting them into a struct (or class) and initializing them however you want. I've had to do this quite a bit for similar things.
BillWoodruff 26-Dec-13 20:12pm    
Thanks, Ron, it's a dance I've done before :)

http://www.codeproject.com/Answers/694721/Enum-declaration-inside-main-method

"An Enum groups together a set of integral Types; you might think of an Enum as a ordered set of named Constants."
Sergey Alexandrovich Kryukov 26-Dec-13 22:38pm    
Not quite. This is simple, but you cannot do exactly what OP wants. Say, OP wants to traverse all enum values and find the uint value, and so on.

This is not a trivial problem which was my concern, too. A while ago, I developed the code for enumerating ("foreach") using an enumeration type, by enum members (not values) and also, to create such structure as the array indexed by an enumeration type. I published a CodeProject article on this topic.

Please see my solution, you can find it interesting.

—SA
BillWoodruff 26-Dec-13 23:31pm    
I look forward to reading, and studying, your article, Sergey.

Happy Holidays !
Sergey Alexandrovich Kryukov 26-Dec-13 23:44pm    
Happy Holidays! Best wishes for New Year!
—SA
I have some better solution. The problem is very interesting an by far not so trivial as it may seem at first glance.

So, please see my article on enumerations: Enumeration Types do not Enumerate! Working around .NET and Language Limitations[^].

In the section 3.5, I explain the type EnumerationIndexedArray<enumerationType, elementValueType> and explain its implementation and usage. So, you can use this array in combination with the possibility to enumerate by enumeration type members (and not by values) I have introduced in my work.

Basically, this is what you can do:
C#
protected enum BoxType
{
    ftyp,
    pdin,
    moov,
    //...
}

//...

EnumeraionIndexedArray<BoxType, uint> boxTypeValues =
    new EnumeraionIndexedArray<BoxType, uint>();

Enumeration<BoxType> boxTypeEnumeration = new Enumeration<BoxType>();
foreach (EnumerationItem<BoxType> item in boxTypeEnumeration) {
   uint intValue = BitConverter.ToUInt32(Encoding.ASCII.GetBytes(item.Name), 0);
   boxTypeEnumeration[item.EnumValue] = intValue; // could be done in one line;
   // written in two for clarity
}
From this moment, you have an object which provides the indexing interface like for arrays, but it is indexed by the values of your type BoxType. It is populated by the values you obtained using BitConverter; and the calculations are done only once. Every time you need this uint value, you just retrieve it from the boxTypeValues object you pre-populated as shown above. The time complexity is the same as indexing the regular array, O(1).

This completely solves your problem.

That was an interesting problem posed in an interesting way, I really appreciate it.

[EDIT]

Now, you have added that some string values which would not make valid member names, such as "©art". You should have told about them in the very beginning. And not what, should I suggest a workaround for you? Fortunately, this is not too hard to do. Your idea is anyway interesting enough, and, with my array indexed by enumeration values you can always add some work-around. Let's think.

Option #1:

First of all, you can introduce some unambiguous mechanism used to manually "decorate" such non-name strings into value names strings, with a function which would parse to "undecorate" them to get the correct value. For example, Undecorate("_copy_art"), or, say, Undecorate("_A9_art") may return "©art". Then the line shown above would be modified as
C#
uint intValue =
    BitConverter.ToUInt32(Encoding.ASCII.GetBytes(Undecorate(item.Name)), 0);

Simple enough, isn't it? I don't know your exact character repertoire used to code your uint values as strings; if I knew it, it could be better. I think if the number of such exclusions as '©' is not so big, you will simply find out convenient "decoration" rule.

Option #2:

Of course, from the very beginning, the obvious solution would be
C#
protected enum BoxType : uint
{
    ftyp = valueFtyp, // this is not what I want to advice!
    pdin = valuePdin, // no, not this way
    moov = valuePmoov, // this is just to show how bad it would be... :-)
    //...
} // where value* are pre-calculated uint values,

but this is what you wanted to avoid from the very beginning. But combining this approach could give you another workaround. You could mix pre-calculated with automatically calculated values:
C#
protected enum BoxType
{ // now, this is what I really advise :-)
    ftyp,
    pdin,
    moov,
    //...
    copyArt = someManuallyPrecalculatedValue,
    somethingElse = someOtherPrecalculatedValue,
    //...
}


Now, part of enumeration member names code the enum values as before, and other names, such as copyArt, are manually pre-calculated. Now, you only need to populate the array the same was as before, but also take into account these two sorts of enum members. How to tell them apart? For example, by the length of the member names, if you use longer names for manually pre-calculated enum names, as shown above. For example:
C#
int autoCodedEnumerationMemberNameLength = 4; // ftyp, pdin, etc.

//...

foreach (EnumerationItem<BoxType> item in boxTypeEnumeration) {
   uint intValue;
   if (item.Name.Length > autoCodedEnumerationMemberNameLength)
       intValue = (uint)item.Value;
   else
       intValue = BitConverter.ToUInt32(Encoding.ASCII.GetBytes(item.Name), 0);
   boxTypeEnumeration[item.EnumValue] = intValue;
}


That's all. You have two workaround option. Now you can chose one depending on your data.

—SA
 
Share this answer
 
v10
Comments
fre_ber 1-Jan-14 10:49am    
This looks great! Unfortunately some of these box types include characters that are not valid as names. For example "url ", note the space at the end, and the ones added by Apple such as "©art" with the copyright char at the beginning.
Sergey Alexandrovich Kryukov 1-Jan-14 13:39pm    
You should have told that in first place, as it could compromise your interesting idea. However, it can still work, as the workaround is not too hard to find. Please see my update to the answer, after [EDIT].

So, I have you two work-around solutions in addition to the main one. Will you finally accept the answer formally (green "Accept" button)? In all cases, you follow-up questions will be welcome.

Happy New Year!

—SA
fre_ber 1-Jan-14 14:14pm    
Great, thanks!
The constraint that the "strings" had to be valid names was something you added, not I. So I am not sure how you'd expect me to anticipate that to be a requirement.

However, your proposed workaround - the first one with an "Undecorator" looks promising. I will try that approach.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900