Tuesday, April 20, 2010

Portable proplib: rw support for gzipped plist files


Today I released version 0.4.1 of the Portable proplib implementation, that is used extensively in XBPS for package metadata, package databases and repository metadata. This new version implements support for reading and writting from/to compressed gzip files with zlib.
The ABI remains compatible and the API has been modified with the
following functions for this task:


prop_{array,dictionary}_internalize_from_zfile():
Internalizes a compressed or uncompressed plist file.


prop_{array,dictionary}_externalize_to_zfile():
Externalizes an array/dictionary into a compressed gzip plist file.


The _zfile variants of these functions support gzip and uncompressed files, so you can safely always use the them and support both types of files.

The following source code in C internalizes a plist file (compressed or uncompressed),
externalizes the result into a compressed file (if argv[1] == 'ext') and prints
the number of objects in the dictionary. If argv[1] == 'int' it's not externalized.


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <prop/proplib.h>

int main(int argc, char **argv)
{
char path[256];
prop_dictionary_t d;

if (argc != 3)
exit(EXIT_FAILURE);

/* Externalize a plist file into a gzipped file */
if (strcmp(argv[1], "ext") == 0) {
d = prop_dictionary_internalize_from_zfile(argv[2]);
snprintf(path, sizeof(path), "%s.gz", argv[2]);
prop_dictionary_externalize_to_zfile(d, path);

/* Internalize a gzip plist file */
} else if (strcmp(argv[1], "int") == 0) {
d = prop_dictionary_internalize_from_zfile(argv[2]);
fprintf(stderr, "%s", prop_dictionary_externalize(d));
}
fprintf(stdout, "Total objs in dictionary: %u\n",
prop_dictionary_count(d));

exit(EXIT_SUCCESS);
}

I got two files, one compressed and another one uncompressed with the same
dictionary (and data) on them:

[juan@nocturno test]$ file pkgidx.plist*
pkgidx.plist: XML document text
pkgidx.plist.gz: gzip compressed data, from Unix, max compression
[juan@nocturno test]$

Now running the example code and redirecting stderr output to /dev/null
(which is too large to show) is able to read the data automagically:

[juan@nocturno test]$ time ./a.out int pkgidx.plist.gz 2>/dev/null
Total objs in dictionary: 3

real 0m0.041s
user 0m0.038s
sys 0m0.002s
[juan@nocturno test]$ time ./a.out int pkgidx.plist 2>/dev/null
Total objs in dictionary: 3

real 0m0.033s
user 0m0.029s
sys 0m0.003s
[juan@nocturno test]$

We can use the 'ext' argument to the example code to magically convert
a non compressed plist file into a compressed gzip file, like:

[juan@nocturno test]$ rm pkgidx.plist.gz
[juan@nocturno test]$ time ./a.out ext pkgidx.plist 2>/dev/null
Total objs in dictionary: 3

real 0m0.111s
user 0m0.096s
sys 0m0.005s
[juan@nocturno test]$
[juan@nocturno test]$ ls -l pkgidx.plist*
-rw-r--r-- 1 juan juan 1009406 abr 20 15:22 pkgidx.plist
-rw-r--r-- 1 juan juan 130546 abr 20 15:49 pkgidx.plist.gz
[juan@nocturno test]$

The portable proplib implementation, maintained by myself, is available from
http://code.google.com/p/portableproplib and will be used in the upcoming XBPS version 0.5.

No comments: