GMimeStream Basics

GMime 2.6 tutorial
Prev | Chapter 4. Getting Down to the Basics | Next

# 4.2. GMimeStream Basics

Before we get too deep into using GMime, it is important to understand how to use the underlying I/O classes since GMime is so very heavily dependant upon them.

If you've looked at the API at all already, you will have probably noticed that the stream functions work very much like those of the standard low-level UNIX I/O functions (those that use file descriptors) but with a few extras taken from the higher-level Standard C I/O API.

Let's take a moment to regres back to our early days of programming where we learned how to write "Hello World!" on the console:

    #include <stdio.h>

    int main (int argc, char **argv)
    {
    	fprintf (stdout, "Hello World!\n");
    	fflush (stdout);

    	return 0;
    }

Everyone should recognize what that program does. The above program, rewritten to use GMime's stream classes would look something like this:

    #include <stdio.h>
    #include <gmime/gmime.h>

    int main (int argc, char **argv)
    {
    	GMimeStream *stream;

    	/* initialize GMime */
    	g_mime_init (0);

    	/* create a stream around stdout */
    	stream = g_mime_stream_file_new (stdout);

    	/* 'printf' */
    	g_mime_stream_printf (stream, "Hello World!\n");

    	/* flush stdout */
    	g_mime_stream_flush (stream);

    	/* free/close the stream */
    	g_object_unref (stream);

    	return 0;
    }

Hopefully, the only thing that may be new to you in either of the above examples is the flushing of the stream after writing to it. Most likely, in both examples, it is an unneeded call, however it is there for completeness and you should probably get into the habbit of flushing a stream after you've finished writing to it. Like fflush(), g_mime_stream_flush() will flush any write-buffers that the previous write-calls may have left.

The first function called in the second example is `g_mime_init` with a value of `0`. If you haven't guessed, `g_mime_init` initializes the GMime library. It takes a single bit-mask argument specifying which options to enable. Currently there is only one optional bit-flag, `GMIME_INIT_FLAG_UTF8` which is the default anyway, so a value of `0` is used here. The UTF-8 flag only exists for historical reasons.

The only other line that should need explaining might be:

    	stream = g_mime_stream_file_new (stdout);

This line creates a new object of type GMimeStreamFile which takes a `FILE*` argument. Once the GMimeStreamFile is created, it takes ownership of the `FILE*` so be careful if you want to be able to ever use that `FILE*` handle again later in your program or if you do not wish for it to be closed when the GMimeStreamFile is closed later.

One way of working around this is to do something like the following example:

    #include <stdio.h>
    #include <unistd.h>
    #include <gmime/gmime.h>

    int main (int argc, char **argv)
    {
    	GMimeStream *stream;

    	/* initialize GMime */
    	g_mime_init (0);

    	/* create a stream around stdout */
    	stream = g_mime_stream_fs_new (dup (fileno (stdout)));

    	/* 'printf' */
    	g_mime_stream_printf (stream, "Hello World!\n");

    	/* flush stdout */
    	g_mime_stream_flush (stream);

    	/* free/close the stream */
    	g_object_unref (stream);

    	return 0;
    }

Here we have made a duplicate copy of stdout to give to `g_mime_stream_fs_new()`. GMimeStreamFs is the second type of stream meant for basic I/O, but instead of using a `FILE*` handle, it instead uses an integer file descriptor. The `fileno()` function returns the integer file descriptor for a given `FILE*` handle. The `dup()` function makes a duplicate of the file descriptor passed to it. More information can be read about these 2 functions by using `man` on your local UNIX system or by reading the Reference Manual for your libc.

There are also some functions to tell GMimeStreamFile, GMimeStreamFs and GMimeStreamMem that they are not the owners of the backend storage and so when they are destroyed, they should not close the file or free the memory buffer (respectively). These functions are:

    void g_mime_stream_file_set_owner (GMimeStreamFile *stream, gboolean owner);
    void g_mime_stream_fs_set_owner (GMimeStreamFs *stream, gboolean owner);
    void g_mime_stream_mem_set_owner (GMimeStreamMem *stream, gboolean owner);

Next, let's examine some of the other stream functions.

    	g_mime_stream_eos (stream);

This function is useful for finding out if the End-Of-Stream has been reached. This is similar in functionality to Standard C's `feof()` function.

    	g_mime_stream_reset (stream);

This function will reset the state of a stream. Usually this only means 'rewinding' to the beginning of the file. For more complex streams, such as GMimeStreamFilter, however, this will also reset the state of all of the filters that have been attached to it (more on this later).

    	g_mime_stream_length (stream);

This function will return the length of the stream if known, or -1 otherwise. For the most part, this function should be avoided unless you absolutely need to know the stream length and there is no other way to get it. The reason to avoid using it is that it may be inaccurate if any filters are to be applied as well as possibly being slow depending on the underlying storage device.

    	g_mime_stream_substream (stream, start, end);

This function will return a substream of the original stream, where the beginning of the new substream is the start offset and the end is the end offset. These start and end offsets MUST be within the bounds of the original stream. Substreams can be useful if you want to only allow reading and writing to a subsection of the original stream.

    	g_mime_stream_read (stream, buf, n);

Like POSIX `read()`, this function will try to read `n` bytes from the stream into `buf`, but be warned that it is not guaranteed to read the full requested buffer size if that much data is not currently available.

    	g_mime_stream_write (stream, buf, n);

Like POSIX `write()` and standard C's `fwrite()`, this function will write a buffer of the specified length to the underlying stream. However, unlike the POSIX `write()` function, it will only fail if an irrecoverable error has occurred and so it is not necessary to loop write attempts until the entire buffer is written.

    	g_mime_stream_seek (stream, offset, GMIME_STREAM_SEEK_SET);
    	g_mime_stream_seek (stream, offset, GMIME_STREAM_SEEK_CUR);
    	g_mime_stream_seek (stream, offset, GMIME_STREAM_SEEK_END);

This function works exactly like the POSIX `lseek()` or standard C's `fseek()` functions.

Prev | Home | Next
Getting Down to the Basics | Up | Stream Class Overview