END_TEST /*- * Test: rec_type_name_nominal * Unit: rec_type_name * Description: * + Get the name of a type. * + The returned name shall be correct. */ START_TEST(rec_type_name_nominal) { rec_type_t type; type = rec_type_new ("range 0 120"); fail_if (type == NULL); rec_type_set_name (type, "age_t"); fail_if (strcmp ("age_t", rec_type_name (type)) != 0); rec_type_destroy (type); }
static void postcat(VSTREAM *fp, VSTRING *buffer, int flags) { int prev_type = 0; int rec_type; struct timeval tv; time_t time; int ch; off_t offset; const char *error_text; char *attr_name; char *attr_value; int rec_flags = (msg_verbose ? REC_FLAG_NONE : REC_FLAG_DEFAULT); int state; /* state machine, input type */ int do_print; /* state machine, output control */ long data_offset; /* state machine, read optimization */ long data_size; /* state machine, read optimization */ #define TEXT_RECORD(rec_type) \ (rec_type == REC_TYPE_CONT || rec_type == REC_TYPE_NORM) /* * See if this is a plausible file. */ if ((ch = VSTREAM_GETC(fp)) != VSTREAM_EOF) { if (!strchr(REC_TYPE_ENVELOPE, ch)) { msg_warn("%s: input is not a valid queue file", VSTREAM_PATH(fp)); return; } vstream_ungetc(fp, ch); } /* * Other preliminaries. */ if (flags & PC_FLAG_PRINT_ENV) vstream_printf("*** ENVELOPE RECORDS %s ***\n", VSTREAM_PATH(fp)); state = PC_STATE_ENV; do_print = (flags & PC_FLAG_PRINT_ENV); data_offset = data_size = -1; /* * Now look at the rest. */ for (;;) { if (flags & PC_FLAG_PRINT_OFFSET) offset = vstream_ftell(fp); rec_type = rec_get_raw(fp, buffer, 0, rec_flags); if (rec_type == REC_TYPE_ERROR) msg_fatal("record read error"); if (rec_type == REC_TYPE_EOF) break; /* * First inspect records that have side effects on the (envelope, * header, body) state machine or on the record reading order. * * XXX Comments marked "Optimization:" identify subtle code that will * likely need to be revised when the queue file organization is * changed. */ #define PRINT_MARKER(flags, fp, offset, type, text) do { \ if ((flags) & PC_FLAG_PRINT_OFFSET) \ vstream_printf("%9lu ", (unsigned long) (offset)); \ if (flags & PC_FLAG_PRINT_RTYPE_DEC) \ vstream_printf("%3d ", (type)); \ vstream_printf("*** %s %s ***\n", (text), VSTREAM_PATH(fp)); \ vstream_fflush(VSTREAM_OUT); \ } while (0) #define PRINT_RECORD(flags, offset, type, value) do { \ if ((flags) & PC_FLAG_PRINT_OFFSET) \ vstream_printf("%9lu ", (unsigned long) (offset)); \ if (flags & PC_FLAG_PRINT_RTYPE_DEC) \ vstream_printf("%3d ", (type)); \ vstream_printf("%s: %s\n", rec_type_name(rec_type), (value)); \ vstream_fflush(VSTREAM_OUT); \ } while (0) if (TEXT_RECORD(rec_type)) { /* This is wrong when the message starts with whitespace. */ if (state == PC_STATE_HEADER && (flags & (PC_MASK_PRINT_TEXT)) && prev_type != REC_TYPE_CONT && TEXT_RECORD(rec_type) && !(is_header(STR(buffer)) || IS_SPACE_TAB(STR(buffer)[0]))) { /* Update the state machine. */ state = PC_STATE_BODY; do_print = (flags & PC_FLAG_PRINT_BODY); /* Optimization: terminate if nothing left to print. */ if (do_print == 0 && (flags & PC_FLAG_PRINT_ENV) == 0) break; /* Optimization: skip to extracted segment marker. */ if (do_print == 0 && (flags & PC_FLAG_PRINT_ENV) && data_offset >= 0 && data_size >= 0 && vstream_fseek(fp, data_offset + data_size, SEEK_SET) < 0) msg_fatal("seek error: %m"); } /* Optional output happens further down below. */ } else if (rec_type == REC_TYPE_MESG) { /* Sanity check. */ if (state != PC_STATE_ENV) msg_warn("%s: out-of-order message content marker", VSTREAM_PATH(fp)); /* Optional output. */ if (flags & PC_FLAG_PRINT_ENV) PRINT_MARKER(flags, fp, offset, rec_type, "MESSAGE CONTENTS"); /* Optimization: skip to extracted segment marker. */ if ((flags & PC_MASK_PRINT_TEXT) == 0 && data_offset >= 0 && data_size >= 0 && vstream_fseek(fp, data_offset + data_size, SEEK_SET) < 0) msg_fatal("seek error: %m"); /* Update the state machine, even when skipping. */ state = PC_STATE_HEADER; do_print = (flags & PC_FLAG_PRINT_HEADER); continue; } else if (rec_type == REC_TYPE_XTRA) { /* Sanity check. */ if (state != PC_STATE_HEADER && state != PC_STATE_BODY) msg_warn("%s: out-of-order extracted segment marker", VSTREAM_PATH(fp)); /* Optional output (terminate preceding header/body line). */ if (do_print && prev_type == REC_TYPE_CONT) VSTREAM_PUTCHAR('\n'); if (flags & PC_FLAG_PRINT_ENV) PRINT_MARKER(flags, fp, offset, rec_type, "HEADER EXTRACTED"); /* Update the state machine. */ state = PC_STATE_ENV; do_print = (flags & PC_FLAG_PRINT_ENV); /* Optimization: terminate if nothing left to print. */ if (do_print == 0) break; continue; } else if (rec_type == REC_TYPE_END) { /* Sanity check. */ if (state != PC_STATE_ENV) msg_warn("%s: out-of-order message end marker", VSTREAM_PATH(fp)); /* Optional output. */ if (flags & PC_FLAG_PRINT_ENV) PRINT_MARKER(flags, fp, offset, rec_type, "MESSAGE FILE END"); /* Terminate the state machine. */ break; } else if (rec_type == REC_TYPE_PTR) { /* Optional output. */ /* This record type is exposed only with '-v'. */ if (do_print) PRINT_RECORD(flags, offset, rec_type, STR(buffer)); /* Skip to the pointer's target record. */ if (rec_goto(fp, STR(buffer)) == REC_TYPE_ERROR) msg_fatal("bad pointer record, or input is not seekable"); continue; } else if (rec_type == REC_TYPE_SIZE) { /* Optional output (here before we update the state machine). */ if (do_print) PRINT_RECORD(flags, offset, rec_type, STR(buffer)); /* Read the message size/offset for the state machine optimizer. */ if (data_size >= 0 || data_offset >= 0) { msg_warn("file contains multiple size records"); } else { if (sscanf(STR(buffer), "%ld %ld", &data_size, &data_offset) != 2 || data_offset <= 0 || data_size <= 0) msg_fatal("invalid size record: %.100s", STR(buffer)); /* Optimization: skip to the message header. */ if ((flags & PC_FLAG_PRINT_ENV) == 0) { if (vstream_fseek(fp, data_offset, SEEK_SET) < 0) msg_fatal("seek error: %m"); /* Update the state machine. */ state = PC_STATE_HEADER; do_print = (flags & PC_FLAG_PRINT_HEADER); } } continue; } /* * Don't inspect side-effect-free records that aren't printed. */ if (do_print == 0) continue; if (flags & PC_FLAG_PRINT_OFFSET) vstream_printf("%9lu ", (unsigned long) offset); if (flags & PC_FLAG_PRINT_RTYPE_DEC) vstream_printf("%3d ", rec_type); switch (rec_type) { case REC_TYPE_TIME: REC_TYPE_TIME_SCAN(STR(buffer), tv); time = tv.tv_sec; vstream_printf("%s: %s", rec_type_name(rec_type), asctime(localtime(&time))); break; case REC_TYPE_WARN: REC_TYPE_WARN_SCAN(STR(buffer), time); vstream_printf("%s: %s", rec_type_name(rec_type), asctime(localtime(&time))); break; case REC_TYPE_CONT: /* REC_TYPE_FILT collision */ if (state == PC_STATE_ENV) vstream_printf("%s: ", rec_type_name(rec_type)); else if (msg_verbose) vstream_printf("unterminated_text: "); vstream_fwrite(VSTREAM_OUT, STR(buffer), LEN(buffer)); if (state == PC_STATE_ENV || msg_verbose || (flags & PC_FLAG_PRINT_OFFSET) != 0) { rec_type = 0; VSTREAM_PUTCHAR('\n'); } break; case REC_TYPE_NORM: if (msg_verbose) vstream_printf("%s: ", rec_type_name(rec_type)); vstream_fwrite(VSTREAM_OUT, STR(buffer), LEN(buffer)); VSTREAM_PUTCHAR('\n'); break; case REC_TYPE_DTXT: /* This record type is exposed only with '-v'. */ vstream_printf("%s: ", rec_type_name(rec_type)); vstream_fwrite(VSTREAM_OUT, STR(buffer), LEN(buffer)); VSTREAM_PUTCHAR('\n'); break; case REC_TYPE_ATTR: error_text = split_nameval(STR(buffer), &attr_name, &attr_value); if (error_text != 0) { msg_warn("%s: malformed attribute: %s: %.100s", VSTREAM_PATH(fp), error_text, STR(buffer)); break; } if (strcmp(attr_name, MAIL_ATTR_CREATE_TIME) == 0) { time = atol(attr_value); vstream_printf("%s: %s", MAIL_ATTR_CREATE_TIME, asctime(localtime(&time))); } else { vstream_printf("%s: %s=%s\n", rec_type_name(rec_type), attr_name, attr_value); } break; default: vstream_printf("%s: %s\n", rec_type_name(rec_type), STR(buffer)); break; } prev_type = rec_type; /* * In case the next record is broken. */ vstream_fflush(VSTREAM_OUT); } }
int GP_ReadGIFEx(GP_IO *io, GP_Context **img, GP_DataStorage *storage, GP_ProgressCallback *callback) { GifFileType *gf; GifRecordType rec_type; GP_Context *res = NULL; GP_Pixel bg; int32_t x, y; int err; errno = 0; #if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5 gf = DGifOpen(io, gif_input_func, NULL); #else gf = DGifOpen(io, gif_input_func); #endif if (gf == NULL) { /* * The giflib uses open() so when we got a failure and errno * is set => open() has failed. * * When errno is not set the file content was not valid so we * set errno to EIO. */ if (errno == 0) errno = EIO; return 1; } GP_DEBUG(1, "Have GIF image %ix%i, %i colors, %i bpp", gf->SWidth, gf->SHeight, gf->SColorResolution, gf->SColorMap ? gf->SColorMap->BitsPerPixel : -1); do { if (DGifGetRecordType(gf, &rec_type) != GIF_OK) { //TODO: error handling GP_DEBUG(1, "DGifGetRecordType() error %s (%i)", gif_err_name(gif_err(gf)), gif_err(gf)); err = EIO; goto err1; } GP_DEBUG(2, "Have GIF record type %s", rec_type_name(rec_type)); switch (rec_type) { case EXTENSION_RECORD_TYPE: if ((err = read_extensions(gf))) goto err1; continue; case IMAGE_DESC_RECORD_TYPE: break; default: continue; } if (DGifGetImageDesc(gf) != GIF_OK) { //TODO: error handling GP_DEBUG(1, "DGifGetImageDesc() error %s (%i)", gif_err_name(gif_err(gf)), gif_err(gf)); err = EIO; goto err1; } if (storage) fill_metadata(gf, storage); GP_DEBUG(1, "Have GIF Image left-top %ix%i, width-height %ix%i," " interlace %i, bpp %i", gf->Image.Left, gf->Image.Top, gf->Image.Width, gf->Image.Height, gf->Image.Interlace, gf->Image.ColorMap ? gf->Image.ColorMap->BitsPerPixel : -1); if (!img) break; res = GP_ContextAlloc(gf->SWidth, gf->SHeight, GP_PIXEL_RGB888); if (res == NULL) { err = ENOMEM; goto err1; } /* If background color is defined, use it */ if (get_bg_color(gf, &bg)) { GP_DEBUG(1, "Filling bg color %x", bg); GP_Fill(res, bg); } /* Now finally read gif image data */ for (y = gf->Image.Top; y < gf->Image.Height; y++) { uint8_t line[gf->Image.Width]; DGifGetLine(gf, line, gf->Image.Width); unsigned int real_y = y; if (gf->Image.Interlace == 64) { real_y = interlace_real_y(gf, y); GP_DEBUG(3, "Interlace y -> real_y %u %u", y, real_y); } //TODO: just now we have only 8BPP for (x = 0; x < gf->Image.Width; x++) GP_PutPixel_Raw_24BPP(res, x + gf->Image.Left, real_y, get_color(gf, line[x])); if (GP_ProgressCallbackReport(callback, y - gf->Image.Top, gf->Image.Height, gf->Image.Width)) { GP_DEBUG(1, "Operation aborted"); err = ECANCELED; goto err2; } } //TODO: now we exit after reading first image break; } while (rec_type != TERMINATE_RECORD_TYPE); DGifCloseFile(gf); /* No Image record found :( */ if (img && !res) { errno = EINVAL; return 1; } if (img) *img = res; return 0; err2: GP_ContextFree(res); err1: DGifCloseFile(gf); errno = err; return 1; }