int xps_parse_metadata(xps_context_t *ctx, xps_part_t *part) { XML_Parser xp; int code; char buf[1024]; char *s; /* Save directory name part */ xps_strlcpy(buf, part->name, sizeof buf); s = strrchr(buf, '/'); if (s) s[0] = 0; /* _rels parts are voodoo: their URI references are from * the part they are associated with, not the actual _rels * part being parsed. */ s = strstr(buf, "/_rels"); if (s) *s = 0; ctx->base_uri = buf; ctx->part_uri = part->name; xp = XML_ParserCreate(NULL); if (!xp) return gs_throw(-1, "cannot create XML parser"); XML_SetUserData(xp, ctx); XML_SetParamEntityParsing(xp, XML_PARAM_ENTITY_PARSING_NEVER); XML_SetStartElementHandler(xp, (XML_StartElementHandler)xps_parse_metadata_imp); code = XML_Parse(xp, (char*)part->data, part->size, 1); XML_ParserFree(xp); ctx->base_uri = NULL; ctx->part_uri = NULL; if (code == 0) return gs_throw1(-1, "cannot parse XML in part: %s", part->name); return 0; }
xps_item_t * xps_parse_xml(xps_context_t *ctx, byte *buf, int len) { xps_parser_t parser; XML_Parser xp; int code; parser.ctx = ctx; parser.root = NULL; parser.head = NULL; parser.error = NULL; parser.compat = 0; xp = XML_ParserCreateNS(NULL, ' '); if (!xp) { gs_throw(-1, "xml error: could not create expat parser"); return NULL; } XML_SetUserData(xp, &parser); XML_SetParamEntityParsing(xp, XML_PARAM_ENTITY_PARSING_NEVER); XML_SetStartElementHandler(xp, (XML_StartElementHandler)on_open_tag); XML_SetEndElementHandler(xp, (XML_EndElementHandler)on_close_tag); XML_SetCharacterDataHandler(xp, (XML_CharacterDataHandler)on_text); code = XML_Parse(xp, (char*)buf, len, 1); if (code == 0) { if (parser.root) xps_free_item(ctx, parser.root); XML_ParserFree(xp); gs_throw1(-1, "xml error: %s", XML_ErrorString(XML_GetErrorCode(xp))); return NULL; } XML_ParserFree(xp); if (parser.compat) xps_process_compatibility(ctx, parser.root); return parser.root; }
int xps_decode_jpeg(xps_context_t *ctx, byte *rbuf, int rlen, xps_image_t *image) { jpeg_decompress_data jddp; stream_DCT_state state; stream_cursor_read rp; stream_cursor_write wp; int code; int wlen; byte *wbuf; jpeg_saved_marker_ptr curr_marker; s_init_state((stream_state*)&state, &s_DCTD_template, ctx->memory); state.report_error = xps_report_error; s_DCTD_template.set_defaults((stream_state*)&state); state.jpeg_memory = ctx->memory; state.data.decompress = &jddp; jddp.templat = s_DCTD_template; jddp.memory = ctx->memory; jddp.scanline_buffer = NULL; if ((code = gs_jpeg_create_decompress(&state)) < 0) return gs_throw(-1, "cannot gs_jpeg_create_decompress"); s_DCTD_template.init((stream_state*)&state); rp.ptr = rbuf - 1; rp.limit = rbuf + rlen - 1; /* read the header only by not having a write buffer */ wp.ptr = 0; wp.limit = 0; /* Set up to save the ICC marker APP2. * According to the spec we should be getting APP1 APP2 and APP13. * Library gets APP0 and APP14. */ jpeg_save_markers(&(jddp.dinfo), 0xe2, 0xFFFF); code = s_DCTD_template.process((stream_state*)&state, &rp, &wp, true); if (code != 1) return gs_throw(-1, "premature EOF or error in jpeg"); /* Check if we had an ICC profile */ curr_marker = jddp.dinfo.marker_list; while (curr_marker != NULL) { if (curr_marker->marker == 0xe2) { /* Found ICC profile. Create a buffer and copy over now. * Strip JPEG APP2 14 byte header */ image->profilesize = curr_marker->data_length - 14; image->profile = xps_alloc(ctx, image->profilesize); if (image->profile) { /* If we can't create it, just ignore */ memcpy(image->profile, &(curr_marker->data[14]), image->profilesize); } break; } curr_marker = curr_marker->next; } image->width = jddp.dinfo.output_width; image->height = jddp.dinfo.output_height; image->comps = jddp.dinfo.output_components; image->bits = 8; image->stride = image->width * image->comps; if (image->comps == 1) image->colorspace = ctx->gray; if (image->comps == 3) image->colorspace = ctx->srgb; if (image->comps == 4) image->colorspace = ctx->cmyk; if (jddp.dinfo.density_unit == 1) { image->xres = jddp.dinfo.X_density; image->yres = jddp.dinfo.Y_density; } else if (jddp.dinfo.density_unit == 2) { image->xres = (int)(jddp.dinfo.X_density * 2.54 + 0.5); image->yres = (int)(jddp.dinfo.Y_density * 2.54 + 0.5); } else { image->xres = 96; image->yres = 96; } wlen = image->stride * image->height; wbuf = xps_alloc(ctx, wlen); if (!wbuf) return gs_throw1(gs_error_VMerror, "out of memory allocating samples: %d", wlen); image->samples = wbuf; wp.ptr = wbuf - 1; wp.limit = wbuf + wlen - 1; code = s_DCTD_template.process((stream_state*)&state, &rp, &wp, true); if (code != EOFC) return gs_throw1(-1, "error in jpeg (code = %d)", code); gs_jpeg_destroy(&state); return gs_okay; }
static int xps_report_error(stream_state * st, const char *str) { (void) gs_throw1(-1, "%s", str); return 0; }
/* (de)crypt a section of text--the procedure is the same * in each direction. see strimpl.h for return codes. */ static int s_aes_process(stream_state * ss, stream_cursor_read * pr, stream_cursor_write * pw, bool last) { stream_aes_state *const state = (stream_aes_state *) ss; const unsigned char *limit; const long in_size = pr->limit - pr->ptr; const long out_size = pw->limit - pw->ptr; unsigned char temp[16]; int status = 0; /* figure out if we're going to run out of space */ if (in_size > out_size) { limit = pr->ptr + out_size; status = 1; /* need more output space */ } else { limit = pr->limit; status = last ? EOFC : 0; /* need more input */ } /* set up state and context */ if (state->ctx == NULL) { /* allocate the aes context. this is a public struct but it contains internal pointers, so we need to store it separately in immovable memory like any opaque structure. */ state->ctx = (aes_context *)gs_alloc_bytes_immovable(state->memory, sizeof(aes_context), "aes context structure"); if (state->ctx == NULL) { gs_throw(gs_error_VMerror, "could not allocate aes context"); return ERRC; } if (state->keylength < 1 || state->keylength > SAES_MAX_KEYLENGTH) { gs_throw1(gs_error_rangecheck, "invalid aes key length (%d bytes)", state->keylength); return ERRC; } aes_setkey_dec(state->ctx, state->key, state->keylength * 8); } if (!state->initialized) { /* read the initialization vector from the first 16 bytes */ if (in_size < 16) return 0; /* get more data */ memcpy(state->iv, pr->ptr + 1, 16); state->initialized = 1; pr->ptr += 16; } /* decrypt available blocks */ while (pr->ptr + 16 <= limit) { aes_crypt_cbc(state->ctx, AES_DECRYPT, 16, state->iv, pr->ptr + 1, temp); pr->ptr += 16; if (last && pr->ptr == pr->limit) { /* we're on the last block; unpad if necessary */ int pad; if (state->use_padding) { /* we are using RFC 1423-style padding, so the last byte of the plaintext gives the number of bytes to discard */ pad = temp[15]; if (pad < 1 || pad > 16) { gs_throw1(gs_error_rangecheck, "invalid aes padding byte (0x%02x)", (unsigned char)pad); return ERRC; } } else { /* not using padding */ pad = 0; } memcpy(pw->ptr + 1, temp, 16 - pad); pw->ptr += 16 - pad; return EOFC; } memcpy(pw->ptr + 1, temp, 16); pw->ptr += 16; } /* if we got to the end of the file without triggering the padding check, the input must not have been a multiple of 16 bytes long. complain. */ if (status == EOFC) { gs_throw(gs_error_rangecheck, "aes stream isn't a multiple of 16 bytes"); return ERRC; } return status; }
static int xps_true_callback_glyph_name(gs_font *pfont, gs_glyph glyph, gs_const_string *pstr) { /* This function is copied verbatim from plfont.c */ int table_length; int table_offset; ulong format; uint numGlyphs; uint glyph_name_index; const byte *postp; /* post table pointer */ /* guess if the font type is not truetype */ if ( pfont->FontType != ft_TrueType ) { glyph -= 29; if ( glyph >= 0 && glyph < 258 ) { pstr->data = (byte*) pl_mac_names[glyph]; pstr->size = strlen((char*)pstr->data); return 0; } else { return gs_throw1(-1, "glyph index %lu out of range", (ulong)glyph); } } table_offset = xps_find_sfnt_table((xps_font_t*)pfont->client_data, "post", &table_length); /* no post table */ if (table_offset < 0) return gs_throw(-1, "no post table"); /* this shoudn't happen but... */ if ( table_length == 0 ) return gs_throw(-1, "zero-size post table"); ((gs_font_type42 *)pfont)->data.string_proc((gs_font_type42 *)pfont, table_offset, table_length, &postp); format = u32(postp); /* Format 1.0 (mac encoding) is a simple table see the TT spec. * We don't implement this because we don't see it in practice. * Format 2.5 is deprecated. * Format 3.0 means that there is no post data in the font file. * We see this a lot but can't do much about it. * The only format we support is 2.0. */ if ( format != 0x20000 ) { /* Invent a name if we don't know the table format. */ char buf[32]; sprintf(buf, "glyph%d", (int)glyph); pstr->data = (byte*)buf; pstr->size = strlen((char*)pstr->data); return 0; } /* skip over the post header */ numGlyphs = u16(postp + 32); if ( glyph < 0 || glyph > numGlyphs - 1) { return gs_throw1(-1, "glyph index %lu out of range", (ulong)glyph); } /* glyph name index starts at post + 34 each entry is 2 bytes */ glyph_name_index = u16(postp + 34 + (glyph * 2)); /* this shouldn't happen */ if ( glyph_name_index < 0 && glyph_name_index > 0x7fff ) return gs_throw(-1, "post table format error"); /* mac easy */ if ( glyph_name_index < 258 ) { // dprintf2("glyph name (mac) %d = %s\n", glyph, pl_mac_names[glyph_name_index]); pstr->data = (byte*) pl_mac_names[glyph_name_index]; pstr->size = strlen((char*)pstr->data); return 0; } /* not mac */ else { byte *mydata; /* and here's the tricky part */ const byte *pascal_stringp = postp + 34 + (numGlyphs * 2); /* 0 - 257 lives in the mac table above */ glyph_name_index -= 258; /* The string we want is the index'th pascal string, * so we "hop" to each length byte "index" times. */ while (glyph_name_index > 0) { pascal_stringp += ((int)(*pascal_stringp)+1); glyph_name_index--; } /* length byte */ pstr->size = (int)(*pascal_stringp); /* + 1 is for the length byte */ pstr->data = pascal_stringp + 1; /* sanity check */ if ( pstr->data + pstr->size > postp + table_length || pstr->data - 1 < postp) return gs_throw(-1, "data out of range"); /* sigh - we have to allocate a copy of the data - by the * time a high level device makes use of it the font data * may be freed. This is a necessary leak. */ mydata = gs_alloc_bytes(pfont->memory, pstr->size + 1, "glyph to name"); if ( mydata == 0 ) return -1; memcpy(mydata, pascal_stringp + 1, pstr->size); pstr->data = mydata; mydata[pstr->size] = 0; return 0; } }
int xps_decode_jpegxr(xps_context_t *ctx, byte *buf, int len, xps_image_t *output) { FILE *file; char *name = xps_alloc(ctx, gp_file_name_sizeof); struct state state; jxr_container_t container; jxr_image_t image; int offset, alpha_offset; int rc; if (!name) { return gs_throw(gs_error_VMerror, "cannot allocate scratch file name buffer"); } memset(output, 0, sizeof(*output)); file = gp_open_scratch_file(ctx->memory, "jpegxr-scratch-", name, "wb+"); if (!file) { xps_free(ctx, name); return gs_throw(gs_error_invalidfileaccess, "cannot open scratch file"); } rc = fwrite(buf, 1, len, file); if (rc != len) { xps_free(ctx, name); return gs_throw(gs_error_invalidfileaccess, "cannot write to scratch file"); } fseek(file, 0, SEEK_SET); container = jxr_create_container(); rc = jxr_read_image_container(container, file); if (rc < 0) { xps_free(ctx, name); return gs_throw1(-1, "jxr_read_image_container: %s", jxr_error_string(rc)); } offset = jxrc_image_offset(container, 0); alpha_offset = jxrc_alpha_offset(container, 0); output->xres = jxrc_width_resolution(container, 0); output->yres = jxrc_height_resolution(container, 0); image = jxr_create_input(); jxr_set_PROFILE_IDC(image, 111); jxr_set_LEVEL_IDC(image, 255); jxr_set_pixel_format(image, jxrc_image_pixelformat(container, 0)); jxr_set_container_parameters(image, jxrc_image_pixelformat(container, 0), jxrc_image_width(container, 0), jxrc_image_height(container, 0), jxrc_alpha_offset(container, 0), jxrc_image_band_presence(container, 0), jxrc_alpha_band_presence(container, 0), 0); jxr_set_block_output(image, xps_decode_jpegxr_block); state.ctx = ctx; state.output = output; jxr_set_user_data(image, &state); fseek(file, offset, SEEK_SET); rc = jxr_read_image_bitstream(image, file); if (rc < 0) { xps_free(ctx, name); return gs_throw1(-1, "jxr_read_image_bitstream: %s", jxr_error_string(rc)); } jxr_destroy(image); if (alpha_offset > 0) { image = jxr_create_input(); jxr_set_PROFILE_IDC(image, 111); jxr_set_LEVEL_IDC(image, 255); jxr_set_pixel_format(image, jxrc_image_pixelformat(container, 0)); jxr_set_container_parameters(image, jxrc_image_pixelformat(container, 0), jxrc_image_width(container, 0), jxrc_image_height(container, 0), jxrc_alpha_offset(container, 0), jxrc_image_band_presence(container, 0), jxrc_alpha_band_presence(container, 0), 0); jxr_set_block_output(image, xps_decode_jpegxr_alpha_block); state.ctx = ctx; state.output = output; jxr_set_user_data(image, &state); fseek(file, alpha_offset, SEEK_SET); rc = jxr_read_image_bitstream(image, file); if (rc < 0) { xps_free(ctx, name); return gs_throw1(-1, "jxr_read_image_bitstream: %s", jxr_error_string(rc)); } jxr_destroy(image); } jxr_destroy_container(container); fclose(file); unlink(name); xps_free(ctx, name); return gs_okay; }
int gslt_render_font_glyph(gs_state *pgs, gslt_font_t *xf, gs_matrix *tm, int gid, gslt_glyph_bitmap_t *slot) { gs_fixed_point subpixel = {0, 0}; /* we don't use subpixel accurate device metrics */ gs_log2_scale_point oversampling = {0, 0}; /* we don't use oversampling */ gs_text_params_t params; gs_text_enum_t *textenum; gs_matrix matrix; cached_fm_pair *ppair; cached_char *cc; int code; /* get the real font matrix (this is a little dance) */ gs_setfont(pgs, xf->font); /* set pgs->font and invalidate existing charmatrix */ gs_setcharmatrix(pgs, tm); /* set the charmatrix to ctm * tm */ gs_currentcharmatrix(pgs, &matrix, true); /* extract charmatrix (and multiply by FontMatrix) */ // dprintf4("tm = [%g %g %g %g]\n", matrix.xx, matrix.xy, matrix.yx, matrix.yy); /* find the font/matrix pair (or add it) */ code = gx_lookup_fm_pair(xf->font, &matrix, &oversampling, false, &ppair); if (code != 0) return gs_throw(-1, "cannot gx_lookup_fm_pair()"); cc = gx_lookup_cached_char(xf->font, ppair, gid, 0, 1, &subpixel); if (!cc) { /* No luck ... now we need to get it into the cache somehow. * * We do this by rendering one glyph (that's why we need a device and pgs). * The renderer always renders the bitmap into the cache, and draws * from out of the cache when blitting to the device. * * Things don't get evicted from the cache until there is a collision, * so we have a safe window to snarf it back out of the cache * after it's been drawn to the device. */ // dprintf1("cache miss for glyph %d\n", gid); params.operation = TEXT_FROM_SINGLE_GLYPH | TEXT_DO_DRAW | TEXT_RETURN_WIDTH; params.data.d_glyph = gid; params.size = 1; gs_moveto(pgs, 100.0, 100.0); // why? code = gs_text_begin(pgs, ¶ms, xf->font->memory, &textenum); if (code != 0) return gs_throw1(-1, "cannot gs_text_begin() (%d)", code); code = gs_text_process(textenum); if (code != 0) return gs_throw1(-1, "cannot gs_text_process() (%d)", code); gs_text_release(textenum, "gslt font render"); cc = gx_lookup_cached_char(xf->font, ppair, gid, 0, 1, &subpixel); if (!cc) { /* merde! it rendered but was not placed in the cache. */ return gs_throw(-2, "cannot render from cache"); } } /* copy values from the cache into the client struct */ slot->w = cc->width; slot->h = cc->height; slot->stride = cc_raster(cc); slot->lsb = fixed2int(cc->offset.x); slot->top = fixed2int(cc->offset.y); slot->cc = cc; slot->data = cc_bits(cc); gx_retain_cached_char(cc); #define XXX #ifndef XXX static int xxx = 0; /* declaration out in the wild not allowed in ansi c */ dprintf1("glyph %d\n", xxx); debug_dump_bitmap(cc_bits(cc), cc_raster(cc), cc->height, ""); { char fn[32]; sprintf(fn, "glyph%d.pbm", xxx); FILE *fo = fopen(fn, "wb"); if (!fo) return -1; fprintf(fo, "P4\n%d %d\n", cc->width, cc->height); int y; int s = (cc->width + 7) / 8; for (y = 0; y < cc->height; y++) fwrite(cc_bits(cc) + y * cc_raster(cc), 1, s, fo); fclose(fo); } xxx ++; #endif return 0; }
int xps_parse_fixed_page(xps_context_t *ctx, xps_part_t *part) { xps_item_t *root, *node; xps_resource_t *dict; char *width_att; char *height_att; char base_uri[1024]; char *s; int code; if_debug1m('|', ctx->memory, "doc: parsing page %s\n", part->name); xps_strlcpy(base_uri, part->name, sizeof base_uri); s = strrchr(base_uri, '/'); if (s) s[1] = 0; root = xps_parse_xml(ctx, part->data, part->size); if (!root) return gs_rethrow(-1, "cannot parse xml"); if (strcmp(xps_tag(root), "FixedPage")) return gs_throw1(-1, "expected FixedPage element (found %s)", xps_tag(root)); width_att = xps_att(root, "Width"); height_att = xps_att(root, "Height"); if (!width_att) return gs_throw(-1, "FixedPage missing required attribute: Width"); if (!height_att) return gs_throw(-1, "FixedPage missing required attribute: Height"); dict = NULL; /* Setup new page */ { gs_memory_t *mem = ctx->memory; gs_state *pgs = ctx->pgs; gx_device *dev = gs_currentdevice(pgs); gs_param_float_array fa; float fv[2]; gs_c_param_list list; gs_c_param_list_write(&list, mem); fv[0] = atoi(width_att) / 96.0 * 72.0; fv[1] = atoi(height_att) / 96.0 * 72.0; fa.persistent = false; fa.data = fv; fa.size = 2; code = param_write_float_array((gs_param_list *)&list, ".MediaSize", &fa); if ( code >= 0 ) { gs_c_param_list_read(&list); code = gs_putdeviceparams(dev, (gs_param_list *)&list); } gs_c_param_list_release(&list); /* nb this is for the demo it is wrong and should be removed */ gs_initgraphics(pgs); /* 96 dpi default - and put the origin at the top of the page */ gs_initmatrix(pgs); code = gs_scale(pgs, 72.0/96.0, -72.0/96.0); if (code < 0) return gs_rethrow(code, "cannot set page transform"); code = gs_translate(pgs, 0.0, -atoi(height_att)); if (code < 0) return gs_rethrow(code, "cannot set page transform"); code = gs_erasepage(pgs); if (code < 0) return gs_rethrow(code, "cannot clear page"); } /* Pre-parse looking for transparency */ ctx->has_transparency = 0; for (node = xps_down(root); node; node = xps_next(node)) { if (!strcmp(xps_tag(node), "FixedPage.Resources") && xps_down(node)) if (xps_resource_dictionary_has_transparency(ctx, base_uri, xps_down(node))) ctx->has_transparency = 1; if (xps_element_has_transparency(ctx, base_uri, node)) ctx->has_transparency = 1; } /* save the state with the original device before we push */ gs_gsave(ctx->pgs); if (ctx->use_transparency && ctx->has_transparency) { code = gs_push_pdf14trans_device(ctx->pgs, false); if (code < 0) { gs_grestore(ctx->pgs); return gs_rethrow(code, "cannot install transparency device"); } } /* Draw contents */ for (node = xps_down(root); node; node = xps_next(node)) { if (!strcmp(xps_tag(node), "FixedPage.Resources") && xps_down(node)) { code = xps_parse_resource_dictionary(ctx, &dict, base_uri, xps_down(node)); if (code) { gs_pop_pdf14trans_device(ctx->pgs, false); gs_grestore(ctx->pgs); return gs_rethrow(code, "cannot load FixedPage.Resources"); } } code = xps_parse_element(ctx, base_uri, dict, node); if (code) { gs_pop_pdf14trans_device(ctx->pgs, false); gs_grestore(ctx->pgs); return gs_rethrow(code, "cannot parse child of FixedPage"); } } if (ctx->use_transparency && ctx->has_transparency) { code = gs_pop_pdf14trans_device(ctx->pgs, false); if (code < 0) { gs_grestore(ctx->pgs); return gs_rethrow(code, "cannot uninstall transparency device"); } } /* Flush page */ { code = xps_show_page(ctx, 1, true); /* copies, flush */ if (code < 0) { gs_grestore(ctx->pgs); return gs_rethrow(code, "cannot flush page"); } } /* restore the original device, discarding the pdf14 compositor */ gs_grestore(ctx->pgs); if (dict) { xps_free_resource_dictionary(ctx, dict); } xps_free_item(ctx, root); return 0; }