/** * Read a string from the file. * The semantic is like the C fgets() function. */ char* fzgets(char *s, int n, adv_fz* f) { char* r; if (n < 2) { r = 0; } else { int c = fzgetc(f); if (c == EOF) { r = 0; } else { r = s; while (n > 1) { *s++ = c; --n; if (c == '\n') break; if (n > 1) c = fzgetc(f); } if (n) { *s = 0; } else { r = 0; } } } return r; }
static void pcx_decode(uint8* buffer, unsigned size, adv_fz* f, struct pcx_decode_state* state, unsigned delta) { while (size) { unsigned run; if (!state->count) { uint8 c = fzgetc(f); if ((c & 0xC0) == 0xC0) { state->count = (c & 0x3F); state->value = fzgetc(f); } else { state->count = 1; state->value = c; } } run = state->count; if (run > size) run = size; state->count -= run; size -= run; while (run) { *buffer = state->value; buffer += delta; --run; } } }
static void pcx_ignore(unsigned size, adv_fz* f, struct pcx_decode_state* state) { while (size) { unsigned run; if (!state->count) { uint8 c = fzgetc(f); if ((c & 0xC0) == 0xC0) { state->count = (c & 0x3F); state->value = fzgetc(f); } else { state->count = 1; state->value = c; } } run = state->count; if (run > size) run = size; state->count -= run; size -= run; } }
/** * Load a .pcx file in a bitmap. * Only the 8 and 24 bits format are supported. * \param f File to load. * \param rgb Where to put the palette information. it must point to a vector of 256 elements. * \param rgb_max Where to put the number of palette entries. * \return The loaded bitmap or 0 on error. */ adv_bitmap* adv_bitmap_load_pcx(adv_color_rgb* rgb, unsigned* rgb_max, adv_fz* f) { struct pcx_header_t h; adv_bitmap* bitmap; unsigned width, height, depth; if (pcx_header_read(f, &h)!=0) { goto out; } /* limitations */ if (h.bits_per_pixel != 8) { goto out; } if (h.planes != 1 && h.planes != 3) { goto out; } width = h.x_max - h.x_min + 1; height = h.y_max - h.y_min + 1; depth = h.planes; bitmap = adv_bitmap_alloc(width, height, depth); if (!bitmap) { goto out; } if (depth == 1) { unsigned i; unsigned y; for(y=0; y<height; ++y) { struct pcx_decode_state state; uint8* dst_off = adv_bitmap_line(bitmap, y); state.count = 0; pcx_decode(dst_off, width, f, &state, 1); pcx_ignore(h.bytes_per_line - width, f, &state); if (state.count!=0) goto out_bitmap; } if (fzgetc(f)!=12) goto out_bitmap; for (i=0; i<256; ++i) { rgb[i].red = fzgetc(f); rgb[i].green = fzgetc(f); rgb[i].blue = fzgetc(f); } *rgb_max = 256; } else { unsigned y; for(y=0; y<height; ++y) { struct pcx_decode_state state; uint8* dst_off = adv_bitmap_line(bitmap, y); state.count = 0; pcx_decode(dst_off, width, f, &state, 3); pcx_ignore(h.bytes_per_line - width, f, &state); pcx_decode(dst_off + 1, width, f, &state, 3); pcx_ignore(h.bytes_per_line - width, f, &state); pcx_decode(dst_off + 2, width, f, &state, 3); pcx_ignore(h.bytes_per_line - width, f, &state); if (state.count!=0) goto out_bitmap; } } return bitmap; out_bitmap: adv_bitmap_free(bitmap); out: return 0; }
/** * Load a .ico file in a bitmap. * Only the 16 and 256 color formats are supported. * \param f File to load. * \param rgb Where to put the palette information. it must point to a vector of 256 elements. * \param rgb_max Where to put the number of palette entries. * \param bitmap_mask Where to put the mask bitmap. * \return The loaded bitmap or 0 on error. */ adv_bitmap* adv_bitmap_load_icon(adv_color_rgb* rgb, unsigned* rgb_max, adv_bitmap** bitmap_mask, adv_fz* f) { adv_bitmap* bitmap; struct icon_header_t header; struct icon_entry_t* entry; int i; if (icon_header_read(f, &header) != 0) goto out; if (header.reserved != 0) goto out; if (header.type != 1) goto out; if (header.count < 1) goto out; entry = malloc(header.count * sizeof(struct icon_entry_t)); if (!entry) goto out; for(i=0;i<header.count;++i) { if (icon_entry_read(f, entry + i)!=0) goto out_entry; } for(i=0;i<header.count;++i) { struct icon_bitmap_header_t bitmap_header; unsigned j, y; unsigned colors; if (entry[i].color == 0) { colors = 256; if (entry[i].bit != 8 && entry[i].bit != 0) /* 0 is out of standard but acceptable */ continue; /* unsupported */ } else if (entry[i].color == 16) { colors = 16; if (entry[i].bit != 4 && entry[i].bit != 0) /* 0 is out of standard but acceptable */ continue; /* unsupported */ } else { continue; /* unsupported */ } if (entry[i].planes != 1 && entry[i].planes != 0) /* 0 is out of standard but acceptable */ continue; /* unsupported */ if (fzseek(f, entry[i].offset, SEEK_SET)!=0) goto out_entry; if (icon_bitmap_header_read(f, &bitmap_header) != 0) goto out_entry; if (colors == 256) { if (bitmap_header.bit != 8) continue; /* unsupported */ } else if (colors == 16) { if (bitmap_header.bit != 4) continue; /* unsupported */ } if (bitmap_header.planes != 1) continue; /* unsupported */ if (bitmap_header.compression != 0) continue; /* unsupported */ for(j=0;j<colors;++j) { struct icon_rgb_t color; if (icon_rgb_read(f, &color) != 0) goto out_entry; rgb[j].red = color.red; rgb[j].green = color.green; rgb[j].blue = color.blue; } *rgb_max = colors; bitmap = adv_bitmap_alloc(entry[i].width, entry[i].height, 1); if (!bitmap) goto out_entry; *bitmap_mask = adv_bitmap_alloc(entry[i].width, entry[i].height, 1); if (!*bitmap_mask) goto out_bitmap; if (colors == 256) { /* read bitmap xor data (8 bit per pixel) */ for(y=0;y<bitmap->size_y;++y) { unsigned char* line = adv_bitmap_line(bitmap, bitmap->size_y - y - 1); if (fzread(line, bitmap->size_x*bitmap->bytes_per_pixel, 1, f)!=1) goto out_bitmap_mask; } } else if (colors == 16) { /* read bitmap xor data (4 bit per pixel) */ for(y=0;y<bitmap->size_y;++y) { int k; unsigned char* line = adv_bitmap_line(bitmap, bitmap->size_y - y - 1); if (fzread(line, bitmap->size_x / 2, 1, f)!=1) goto out_bitmap_mask; /* convert */ for(k=bitmap->size_x-1;k>=0;--k) { if (k & 1) line[k] = line[k/2] & 0xF; else line[k] = line[k/2] >> 4; } } } /* read bitmap mask data (1 bit per pixel) */ for(y=0;y<bitmap->size_y;++y) { unsigned x ; unsigned char* line = adv_bitmap_line(*bitmap_mask, bitmap->size_y - y - 1); x = 0; while (x < bitmap->size_x) { unsigned bc; int b = fzgetc(f); if (b==EOF) goto out_bitmap_mask; if (x + 8 > bitmap->size_x) bc = bitmap->size_x - x; /* waste unused bit */ else bc = 8; x += bc; while (bc) { if (b & 0x80) *line = 0; else *line = 1; b = b << 1; ++line; --bc; } } } free(entry); return bitmap; } goto out_entry; out_bitmap_mask: adv_bitmap_free(*bitmap_mask); out_bitmap: adv_bitmap_free(bitmap); out_entry: free(entry); out: return 0; }