by Richard H. Pizzarro <rhp@netscape.com>
This module, libmime, implements a general-purpose MIME parser. One of the methods provided by this parser is the ability to emit an HTML representation of the data stream.
The parser is object-oriented. There is a class for each MIME type, and each class is responsible for parsing itself, and/or handing the input data off to one of its child objects.
The definition of these classes is somewhat idiosyncratic and consists of an internally defined object system, instead of C++.
There is one header file and one source file for each class (for example, the MimeInlineText class is defined in "mimetext.h" and "mimetext.c".) Each header file follows the following boiler-plate form:
typedefs
These come first to avoid circular dependencies.
typedef struct FoobarClass FoobarClass;
typedef struct Foobar
Foobar;
Class Declaration
Theis structure defines the callback routines and other per-class data
of the class defined in this module.
struct FoobarClass {
ParentClass superclass;
...any callbacks or class-variables...
};
Class Definition
This variable holds an instance of the one-and-only class record; the
various instances of this class point to this object. (One interrogates
the type of an instance by comparing the value of its class pointer with
the address of this variable.)
extern FoobarClass foobarClass;
Instance Declaration
Theis structure defines the per-instance data of an object, and a pointer
to the corresponding class record.
struct Foobar {
Parent parent;
...any instance variables...
};
Then, in the corresponding .c file, the following structure is used:
Class Definition
First we pull in the appropriate include file (which includes all necessary
include files for the parent classes) and then we define the class object
using the MimeDefClass macro:
#include "foobar.h"
#define MIME_SUPERCLASS parentlClass
MimeDefClass(Foobar, FoobarClass, foobarClass,
&MIME_SUPERCLASS);
The definition of MIME_SUPERCLASS is just to move most of the knowlege of the exact class hierarchy up to the file's header, instead of it being scattered through the various methods; see below.
Method Declarations
We will be putting function pointers into the class object, so we declare
them here. They can generally all be static, since nobody outside
of this file needs to reference them by name; all references to these routines
should be through the class object.
extern int FoobarMethod(Foobar *);
...etc...
Class Initialization Function
The MimeDefClass macro expects us to define a function which will finish
up any initialization of the class object that needs to happen before the
first time it is instantiated. Its name must be of the form "<class>Initialize",
and it should initialize the various method slots in the class as appropriate.
Any methods or class variables which this class does not wish to override
will be automatically inherited from the parent class (by virtue of its
class-initialization function having been run first.) Each class
object will only be initialized once.
static int
FoobarClassInitialize(FoobarClass *class)
{
class->method = FoobarMethod.
...etc...
}
Method Definitions
Next come the definitions of the methods we referred to in the class-init
function. The way to access earlier methods (methods defined on the
superclass) is to simply extract them from the superclass's object. But
note that you CANNOT get at methods by indirecting through object->class->superclass:
that will only work to one level, and will go into a loop if some subclass
tries to continue on this method.
The easiest way to do this is to make use of the MIME_SUPERCLASS macro that was defined at the top of the file, as shown below. The alternative to that involves typing the literal name of the direct superclass of the class defined in this file, which will be a maintenance headache if the class hierarchy changes. If you use the MIME_SUPERCLASS idiom, then a textual change is required in only one place if this class's superclass changes.
static void
Foobar_finalize (MimeObject *object)
{
((MimeObjectClass*)&MIME_SUPERCLASS)->finalize(object);
// RIGHT
parentClass.whatnot.object.finalize(object);
// (works...)
object->class->superclass->finalize(object);
// WRONG!!
}
The class hierarchy is:
MimeObject (abstract)
|
|--- MimeContainer (abstract)
| |
| |--- MimeMultipart
(abstract)
| |
|
| |
|--- MimeMultipartMixed
| |
|
| |
|--- MimeMultipartDigest
| |
|
| |
|--- MimeMultipartParallel
| |
|
| |
|--- MimeMultipartAlternative
| |
|
| |
|--- MimeMultipartRelated
| |
|
| |
|--- MimeMultipartAppleDouble
| |
|
| |
|--- MimeSunAttachment
| |
|
| |
|--- MimeMultipartSigned (abstract)
| |
| |--- MimeMessage
| |
| |--- MimeUntypedText
|
|--- MimeLeaf (abstract)
| |
| |--- MimeInlineText
(abstract)
| |
|
| |
|--- MimeInlineTextPlain
| |
|
| |
|--- MimeInlineTextHTML
| |
|
| |
|--- MimeInlineTextRichtext
| |
| |
| |
| |--- MimeInlineTextEnriched
| | |
| | |---
MimeInlineTextVCard
| | |
| | |---
MimeInlineTextCalendar
| |
| |--- MimeInlineImage
| |
| |--- MimeExternalObject
|
|--- MimeExternalBody