~ubuntu-branches/ubuntu/karmic/moon/karmic

« back to all changes in this revision

Viewing changes to src/utils.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2009-02-14 12:01:08 UTC
  • Revision ID: james.westby@ubuntu.com-20090214120108-06539vb25vhbd8bn
Tags: upstream-1.0
ImportĀ upstreamĀ versionĀ 1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 
2
/*
 
3
 * utils.cpp: 
 
4
 *
 
5
 * Contact:
 
6
 *   Moonlight List (moonlight-list@lists.ximian.com)
 
7
 *
 
8
 * Copyright 2007 Novell, Inc. (http://www.novell.com)
 
9
 *
 
10
 * See the LICENSE file included with the distribution for details.
 
11
 */
 
12
 
 
13
#ifdef HAVE_CONFIG_H
 
14
#include <config.h>
 
15
#endif
 
16
 
 
17
#include <glib.h>
 
18
#include <glib/gstdio.h>
 
19
 
 
20
#include <stdio.h>
 
21
#include <stdlib.h>
 
22
#include <string.h>
 
23
#include <sys/types.h>
 
24
#include <sys/stat.h>
 
25
#include <unistd.h>
 
26
#include <dirent.h>
 
27
#include <fcntl.h>
 
28
#include <errno.h>
 
29
 
 
30
#include "utils.h"
 
31
 
 
32
 
 
33
 
 
34
/**
 
35
 * MID:
 
36
 * @lo: the low bound
 
37
 * @hi: the high bound
 
38
 *
 
39
 * Finds the midpoint between positive integer values, @lo and @hi.
 
40
 *
 
41
 * Notes: Typically expressed as '(@lo + @hi) / 2', this is incorrect
 
42
 * when @lo and @hi are sufficiently large enough that combining them
 
43
 * would overflow their integer type. To work around this, we use the
 
44
 * formula, '@lo + ((@hi - @lo) / 2)', thus preventing this problem
 
45
 * from occuring.
 
46
 *
 
47
 * Returns the midpoint between @lo and @hi (rounded down).
 
48
 **/
 
49
#define MID(lo, hi) (lo + ((hi - lo) >> 1))
 
50
 
 
51
 
 
52
static guint
 
53
bsearch (GPtrArray *array, bool stable, GCompareFunc cmp, void *item)
 
54
{
 
55
        register guint lo, hi;
 
56
        guint m;
 
57
        int c;
 
58
        
 
59
        if (array->len == 0)
 
60
                return 0;
 
61
        
 
62
        lo = 0, hi = array->len;
 
63
        
 
64
        do {
 
65
                m = MID (lo, hi);
 
66
                if ((c = cmp (&item, &array->pdata[m])) > 0) {
 
67
                        lo = m + 1;
 
68
                        m = lo;
 
69
                } else if (c < 0) {
 
70
                        hi = m;
 
71
                } else if (stable) {
 
72
                        lo = m + 1;
 
73
                        m = lo;
 
74
                } else {
 
75
                        break;
 
76
                }
 
77
        } while (lo < hi);
 
78
        
 
79
        return m;
 
80
}
 
81
 
 
82
void
 
83
g_ptr_array_insert_sorted (GPtrArray *array, GCompareFunc cmp, void *item)
 
84
{
 
85
        guint index = bsearch (array, true, cmp, item);
 
86
        
 
87
        g_ptr_array_insert (array, index, item);
 
88
}
 
89
 
 
90
void
 
91
g_ptr_array_insert (GPtrArray *array, guint index, void *item)
 
92
{
 
93
        guint8 *dest, *src;
 
94
        guint n;
 
95
        
 
96
        if (index >= array->len) {
 
97
                g_ptr_array_add (array, item);
 
98
                return;
 
99
        }
 
100
        
 
101
        g_ptr_array_set_size (array, array->len + 1);
 
102
        
 
103
        dest = ((guint8 *) array->pdata) + (sizeof (void *) * (index + 1));
 
104
        src = ((guint8 *) array->pdata) + (sizeof (void *) * index);
 
105
        n = array->len - index - 1;
 
106
        
 
107
        memmove (dest, src, (sizeof (void *) * n));
 
108
        array->pdata[index] = item;
 
109
}
 
110
 
 
111
static ssize_t
 
112
write_all (int fd, char *buf, size_t len)
 
113
{
 
114
        size_t nwritten = 0;
 
115
        ssize_t n;
 
116
        
 
117
        do {
 
118
                do {
 
119
                        n = write (fd, buf + nwritten, len - nwritten);
 
120
                } while (n == -1 && errno == EINTR);
 
121
                
 
122
                if (n == -1)
 
123
                        return -1;
 
124
                
 
125
                nwritten += n;
 
126
        } while (nwritten < len);
 
127
        
 
128
        return nwritten;
 
129
}
 
130
 
 
131
bool
 
132
ExtractFile (unzFile zip, int fd)
 
133
{
 
134
        char buf[4096];
 
135
        int nread;
 
136
        ssize_t n;
 
137
        
 
138
        do {
 
139
                n = 0;
 
140
                if ((nread = unzReadCurrentFile (zip, buf, sizeof (buf))) > 0) {
 
141
                        if ((n = write_all (fd, buf, nread)) == -1)
 
142
                                break;
 
143
                }
 
144
        } while (nread > 0);
 
145
        
 
146
        if (nread != 0 || n == -1 || fsync (fd) == -1) {
 
147
                close (fd);
 
148
                
 
149
                return false;
 
150
        }
 
151
        
 
152
        close (fd);
 
153
        
 
154
        return true;
 
155
}
 
156
 
 
157
 
 
158
char *
 
159
MakeTempDir (char *tmpdir)
 
160
{
 
161
        char *path, *xxx;
 
162
        int attempts = 0;
 
163
        size_t n;
 
164
        
 
165
        if ((n = strlen (tmpdir)) < 6) {
 
166
                errno = EINVAL;
 
167
                return NULL;
 
168
        }
 
169
        
 
170
        xxx = tmpdir + (n - 6);
 
171
        if (strcmp (xxx, "XXXXXX") != 0) {
 
172
                errno = EINVAL;
 
173
                return NULL;
 
174
        }
 
175
        
 
176
        do {
 
177
                if (!(path = mktemp (tmpdir)))
 
178
                        return NULL;
 
179
                
 
180
                if (g_mkdir (tmpdir, 0700) != -1)
 
181
                        return tmpdir;
 
182
                
 
183
                if (errno != EEXIST) {
 
184
                        // don't bother trying again...
 
185
                        return NULL;
 
186
                }
 
187
                
 
188
                // that path already exists, try a new one...
 
189
                strcpy (xxx, "XXXXXX");
 
190
                attempts++;
 
191
        } while (attempts < 100);
 
192
        
 
193
        return NULL;
 
194
}
 
195
 
 
196
 
 
197
static int
 
198
rmdir_real (GString *path)
 
199
{
 
200
        struct dirent *dent;
 
201
        struct stat st;
 
202
        size_t len;
 
203
        DIR *dir;
 
204
        
 
205
        if (!(dir = opendir (path->str)))
 
206
                return -1;
 
207
        
 
208
        g_string_append_c (path, G_DIR_SEPARATOR);
 
209
        len = path->len;
 
210
        
 
211
        while ((dent = readdir (dir))) {
 
212
                if (!strcmp (dent->d_name, ".") || !strcmp (dent->d_name, ".."))
 
213
                        continue;
 
214
                
 
215
                g_string_truncate (path, len);
 
216
                g_string_append (path, dent->d_name);
 
217
                
 
218
                if (lstat (path->str, &st) == -1)
 
219
                        continue;
 
220
                
 
221
                if (S_ISDIR (st.st_mode))
 
222
                        rmdir_real (path);
 
223
                else
 
224
                        g_unlink (path->str);
 
225
        }
 
226
        
 
227
        closedir (dir);
 
228
        
 
229
        g_string_truncate (path, len - 1);
 
230
        
 
231
        return g_rmdir (path->str);
 
232
}
 
233
 
 
234
//
 
235
// Creates a temporary directory, based on the @filename template
 
236
//
 
237
// Returns: a g-allocated string name that points to the created
 
238
// directory, or NULL on failure
 
239
//
 
240
char *
 
241
CreateTempDir (const char *filename)
 
242
{
 
243
        const char *name;
 
244
        char *path, *buf;
 
245
        
 
246
        if (!(name = strrchr (filename, '/')))
 
247
                name = filename;
 
248
        else
 
249
                name++;
 
250
        
 
251
        buf = g_strdup_printf ("%s.XXXXXX", name);
 
252
        path = g_build_filename (g_get_tmp_dir (), buf, NULL);
 
253
        g_free (buf);
 
254
        
 
255
        if (!MakeTempDir (path)) {
 
256
                g_free (path);
 
257
                return NULL;
 
258
        }
 
259
        
 
260
        return path;
 
261
}
 
262
 
 
263
int
 
264
RemoveDir (const char *dir)
 
265
{
 
266
        GString *path;
 
267
        int rv;
 
268
        
 
269
        path = g_string_new (dir);
 
270
        rv = rmdir_real (path);
 
271
        g_string_free (path, true);
 
272
        
 
273
        return rv;
 
274
}
 
275
 
 
276
int
 
277
CopyFileTo (const char *filename, int fd)
 
278
{
 
279
        char buf[4096];
 
280
        ssize_t nread;
 
281
        int in;
 
282
        
 
283
        if ((in = open (filename, O_RDONLY)) == -1)
 
284
                return -1;
 
285
        
 
286
        do {
 
287
                do {
 
288
                        nread = read (in, buf, sizeof (buf));
 
289
                } while (nread == -1 && errno == EINTR);
 
290
                
 
291
                if (nread == -1)
 
292
                        goto exception;
 
293
                
 
294
                if (nread == 0)
 
295
                        break;
 
296
                
 
297
                if (write_all (fd, buf, nread) == -1)
 
298
                        goto exception;
 
299
        } while (true);
 
300
        
 
301
        if (fsync (fd) == -1)
 
302
                goto exception;
 
303
        
 
304
        close (in);
 
305
        close (fd);
 
306
        
 
307
        return 0;
 
308
        
 
309
exception:
 
310
        
 
311
        close (in);
 
312
        close (fd);
 
313
        
 
314
        return -1;
 
315
}
 
316
 
 
317
cairo_t*
 
318
measuring_context_create (void)
 
319
{
 
320
        cairo_surface_t* surf = cairo_image_surface_create (CAIRO_FORMAT_A1, 1, 1);
 
321
        return cairo_create (surf);
 
322
}
 
323
 
 
324
void
 
325
measuring_context_destroy (cairo_t *cr)
 
326
{
 
327
        cairo_surface_destroy (cairo_get_target (cr));
 
328
        cairo_destroy (cr);
 
329
}
 
330
 
 
331
 
 
332
static ssize_t
 
333
read_internal (int fd, char *buf, size_t n)
 
334
{
 
335
        ssize_t nread;
 
336
        
 
337
        do {
 
338
                nread = read (fd, buf, n);
 
339
        } while (nread == -1 && errno == EINTR);
 
340
        
 
341
        return nread;
 
342
}
 
343
 
 
344
 
 
345
TextStream::TextStream ()
 
346
{
 
347
        cd = (GIConv) -1;
 
348
        bufptr = buffer;
 
349
        buflen = 0;
 
350
        fd = -1;
 
351
        
 
352
        eof = true;
 
353
}
 
354
 
 
355
TextStream::~TextStream ()
 
356
{
 
357
        if (fd != -1)
 
358
                close (fd);
 
359
        
 
360
        if (cd != (GIConv) -1) {
 
361
                g_iconv_close (cd);
 
362
                cd = (GIConv) -1;
 
363
        }
 
364
}
 
365
 
 
366
#define BOM ((gunichar2) 0xFEFF)
 
367
#define ANTIBOM ((gunichar2) 0xFFFE)
 
368
 
 
369
enum Encoding {
 
370
        UTF16_BE,
 
371
        UTF16_LE,
 
372
        UTF32_BE,
 
373
        UTF32_LE,
 
374
        UTF8,
 
375
        UNKNOWN,
 
376
};
 
377
 
 
378
static const char *encoding_names[] = { "UTF-16BE", "UTF-16LE", "UTF-32BE", "UTF-32LE", "UTF-8" };
 
379
 
 
380
 
 
381
bool
 
382
TextStream::OpenBuffer (const char *buf, int size)
 
383
{
 
384
        fmode = false;
 
385
 
 
386
        textbufptr = textbuf = (char *) buf;
 
387
        textbufsize = size;     
 
388
 
 
389
        if (size > 0)
 
390
                eof = false;
 
391
 
 
392
        return ReadBOM (false);
 
393
}
 
394
 
 
395
bool
 
396
TextStream::OpenFile (const char *filename, bool force)
 
397
{
 
398
        fmode = true;
 
399
 
 
400
        if (fd != -1)
 
401
                Close ();
 
402
        
 
403
        if ((fd = open (filename, O_RDONLY)) == -1)
 
404
                return false;
 
405
 
 
406
        return ReadBOM (force);
 
407
}
 
408
 
 
409
bool
 
410
TextStream::ReadBOM (bool force)
 
411
{
 
412
        Encoding encoding = UNKNOWN;
 
413
        gunichar2 bom;
 
414
        ssize_t nread;
 
415
        
 
416
        // prefetch the first chunk of data in order to determine encoding
 
417
        if ((nread = ReadInternal (buffer, sizeof (buffer))) == -1) {
 
418
                Close ();
 
419
                
 
420
                return false;
 
421
        }
 
422
        
 
423
        bufptr = buffer;
 
424
        buflen = nread;
 
425
        
 
426
        if (nread >= 2) {
 
427
                memcpy (&bom, buffer, 2);
 
428
                switch (bom) {
 
429
                case ANTIBOM:
 
430
                        encoding = UTF16_BE;
 
431
                        buflen -= 2;
 
432
                        bufptr += 2;
 
433
                        break;
 
434
                case BOM:
 
435
                        encoding = UTF16_LE;
 
436
                        buflen -= 2;
 
437
                        bufptr += 2;
 
438
                        break;
 
439
                case 0:
 
440
                        if (nread >= 4) {
 
441
                                memcpy (&bom, buffer + 2, 2);
 
442
                                if (bom == ANTIBOM) {
 
443
                                        encoding = UTF32_BE;
 
444
                                        buflen -= 4;
 
445
                                        bufptr += 4;
 
446
                                } else if (bom == BOM) {
 
447
                                        encoding = UTF32_LE;
 
448
                                        buflen -= 4;
 
449
                                        bufptr += 4;
 
450
                                }
 
451
                        }
 
452
                        break;
 
453
                default:
 
454
                        encoding = UTF8;
 
455
                        break;
 
456
                }
 
457
        } else {
 
458
                // assume utf-8
 
459
                encoding = UTF8;
 
460
        }
 
461
        
 
462
        if (encoding == UNKNOWN) {
 
463
                if (!force) {
 
464
                        Close ();
 
465
                        
 
466
                        return false;
 
467
                }
 
468
                
 
469
                encoding = UTF8;
 
470
        }
 
471
        
 
472
        if (encoding != UTF8 && (cd = g_iconv_open ("UTF-8", encoding_names[encoding])) == (GIConv) -1) {
 
473
                Close ();
 
474
                
 
475
                return false;
 
476
        }
 
477
        
 
478
        eof = false;
 
479
        
 
480
        return true;
 
481
}
 
482
 
 
483
void
 
484
TextStream::Close ()
 
485
{
 
486
        if (fd != -1) {
 
487
                close (fd);
 
488
                fd = -1;
 
489
        }
 
490
        
 
491
        if (cd != (GIConv) -1) {
 
492
                g_iconv_close (cd);
 
493
                cd = (GIConv) -1;
 
494
        }
 
495
        
 
496
        bufptr = buffer;
 
497
        buflen = 0;
 
498
        eof = true;
 
499
}
 
500
 
 
501
bool
 
502
TextStream::Eof ()
 
503
{
 
504
        return eof && buflen == 0;
 
505
}
 
506
 
 
507
ssize_t
 
508
TextStream::Read (char *buf, size_t n)
 
509
{
 
510
        size_t inleft = buflen;
 
511
        char *inbuf = bufptr;
 
512
        char *outbuf = buf;
 
513
        size_t outleft = n;
 
514
        ssize_t nread;
 
515
        size_t r;
 
516
        
 
517
        do {
 
518
                if (cd != (GIConv) -1) {
 
519
                        if (g_iconv (cd, &inbuf, &inleft, &outbuf, &outleft) == (size_t) -1) {
 
520
                                switch (errno) {
 
521
                                case E2BIG:
 
522
                                        // not enough space available in the output buffer
 
523
                                        goto out;
 
524
                                case EINVAL:
 
525
                                        // incomplete multibyte character sequence
 
526
                                        goto out;
 
527
                                case EILSEQ:
 
528
                                        // illegal multibyte sequence
 
529
                                        return -1;
 
530
                                default:
 
531
                                        // unknown error, fail
 
532
                                        return -1;
 
533
                                }
 
534
                        }
 
535
                } else {
 
536
                        r = MIN (inleft, outleft);
 
537
                        memcpy (outbuf, inbuf, r);
 
538
                        outleft -= r;
 
539
                        outbuf += r;
 
540
                        inleft -= r;
 
541
                        inbuf += r;
 
542
                }
 
543
                
 
544
                if (outleft == 0 || eof)
 
545
                        break;
 
546
                
 
547
                // buffer more data
 
548
                if (inleft > 0)
 
549
                        memmove (buffer, inbuf, inleft);
 
550
                
 
551
                inbuf = buffer + inleft;
 
552
                if ((nread = ReadInternal (inbuf, sizeof (buffer) - inleft)) <= 0) {
 
553
                        eof = true;
 
554
                        break;
 
555
                }
 
556
                
 
557
                inleft += nread;
 
558
                inbuf = buffer;
 
559
        } while (true);
 
560
        
 
561
        if (eof && cd != (GIConv) -1)
 
562
                g_iconv (cd, NULL, NULL, &outbuf, &outleft);
 
563
        
 
564
out:
 
565
        
 
566
        buflen = inleft;
 
567
        bufptr = inbuf;
 
568
        
 
569
        return (outbuf - buf);
 
570
}
 
571
 
 
572
ssize_t
 
573
TextStream::ReadInternal (char *buffer, ssize_t size)
 
574
{
 
575
        if (fmode) {
 
576
                return read_internal (fd, buffer, size);
 
577
        } else {
 
578
                ssize_t nread = size;
 
579
 
 
580
                if (eof)
 
581
                        return -1;
 
582
 
 
583
                if (textbufptr + size > textbuf + textbufsize) {
 
584
                        eof = true;
 
585
                        nread = textbuf + textbufsize - textbufptr;
 
586
                }
 
587
                memcpy (buffer, textbufptr, nread);
 
588
 
 
589
                textbufptr += nread;
 
590
                                
 
591
                return nread;
 
592
        }
 
593
}
 
594
 
 
595
 
 
596
GArray *double_garray_from_str (const char *s, gint max)
 
597
{
 
598
        char *next = (char *)s;
 
599
        GArray *values = g_array_sized_new (false, true, sizeof (double), max > 0 ? max : 16);
 
600
        double coord = 0.0;
 
601
        guint end = max > 0 ? max : G_MAXINT;
 
602
 
 
603
        while (next && values->len < end) {
 
604
                while (g_ascii_isspace (*next) || *next == ',')
 
605
                        next = g_utf8_next_char (next);
 
606
                
 
607
                if (next) {
 
608
                        errno = 0;
 
609
                        char *prev = next;
 
610
                        coord = g_ascii_strtod (prev, &next);
 
611
                        if (errno != 0 || next == prev)
 
612
                                goto error;
 
613
 
 
614
                        g_array_append_val (values, coord);
 
615
                }
 
616
        }
 
617
 
 
618
error:
 
619
        while (values->len < (guint) max) {
 
620
                coord = 0.0;
 
621
                g_array_append_val (values, coord);
 
622
        }
 
623
 
 
624
        return values;
 
625
}