Re: Bug 687560 "Invalid PDF if /BP pdfmarkswithnon-unique /_objdef"

"SaGS" <[email protected]> Sun, 14 Nov 2004 23:31:18 +0200
Newsgroups gmane.comp.printing.ghostscript.patches
Message-ID <[email protected]>
Dear Igor,

I already did a few changes to the patch, but before posting a new version
we need to agree on some of the points. So, here are some explanations and
questions.

----- Original Message -----
From: "Igor Melichev" <[email protected]>
To: "SaGS" <[email protected]>; <[email protected]>
Sent: Thursday, 4 November 2004 20:01
Subject: Re: [gs-code-review] Fix: Bug 687560 "Invalid PDF if /BP
pdfmarkswithnon-unique /_objdef"


> ...
> First of all, please follow C-style.htm about the code formatting.
> ...

OK. Also got "indent", a 98% friend.


> ...
> 1. The function cos_dict_rename looks some unsmooth
> and it's name isn't enough leading. Could you please
> replace its usage with 2 "traditional" operations :
> remove_entry(old_name),  add_entry(new_name) ?
> (Yes, "rename" saves a few CPU time with
> memory allocations, but it doesn't looks so important optimization).
> Or at least cos_dict_rename to be renamed with
> cos_dict_rename_entry.

(1.A) The name "cos_dict_rename_entry" is fine with me. I considered
cos_dict_rename[_entry]() can be reused when (if ever) other pdfmarks will
be fixed to deal with duplicate distill-time names. (Haven't looked closely,
but it looks this is somehow random at present: /ANN raises an error, /OBJ
implementation is entirely "original" and /NI creates an invalid PDF the
same way as /BP and /PS do at present.)

(1.B) There are already plenty of "put()". If you think that a "remove()"
will be much more useful, then that's fine with me too and I'll change the
code. I suggest the name "cos_dict_unadd()", as its array counterpart. The
function will remove an entry from the dictionary, free the key if
necessary, and return the value (the value will NOT be freed).

Please decide between (1.A) and (1.B).


> 2. I'm unclear with the implementation of the branch
> PDF_NAMECOLLISION_REBUILD.
> Do you really need the "surgery" ?
> I would recommend to do it as this :
> 2.1. Create a new object with pdf_enter_substream;
> 2.2. Copy all useful keys from the old cos dict to the new one;
> 2.3. Remove the old object from the named object list,
> and add the new one;
> 2.4. Cancel and free the old object.
> Note that cos_write_stream_redir, cos_stream_move_all become unnecessary.
> (Well, my suggestion won't work if there are references to
> the old object from others. But in this case your code
> doesn't work also).

Let not say "reference", I consider this word too imprecise. It can mean:
(a) A C pointer. I'll name these "C-ptrs";
(b) References based exclusively on object numbers, those "n 0 R" or "/Rn".
I'll name these "n 0 Refs".
(c) The construct "{OBJNAME}" when it appears in the value part of a
key-value pair and the key is anything except /_objdef. I'll name these
"{OBJRefs}". (These appear only in the source PostScript code, and are
converted internally to "n 0 Refs", but that's not an important fact here.)

With the latest version of the patch, "C-ptrs" remain valid because neither
the old cos_object_t nor the old pdf_resource_t are freed or reallocated,
only their contents may change. Also, the object number and name remain, so
"n 0 Refs" and "{OBJRefs}" are OK too. What exactly makes you believe "in
this case [the] code doesn't work also"?
Notes:
- With the preceding version of the patch, "C-ptrs" didn't survive a
PDF_NAMECOLLISION_REBUILD;
- While I didn't find a "C-ptr" to an XObject, I'm not confident that such
pointers don't exist, nor that they won't be used in the future; for this
reason, I prefer not to change the patch to conform to 2.1 ... 2.4 above.

Regarding the "surgery", I don't like the idea either, because it's a source
of errors. In fact, in the meantime I discovered that, even if the patient
did not die, the surgery was incomplete,
pdev->accumulating_substream_resource needing to be patched too.

Given this situation, I think the options are:
(2.A) Change pdf_alloc_aside() as it was in the preceding version of the
patch. It will continue to output an "aside", but the added "pcofwd"
parameter allows the caller, by setting this to !=NULL, to feed-in whatever
pieces of the future "aside" are already available. This way, the right
object is used in the first place, all those intricate connections will be
made to the right object, and "surgery" will be unnecessary.
(pdf_enter_substream() and pdf_open-aside() will also need this extra
parameter, but their logic doesn't really change, they only pass this
parameter to the next function.) A VARIATION of this: don't add an extra
parameter, but make the existing "ppres" to be an in/out parameter rather
than an out parameter. (In this 2nd case, I identified a few places in 4
files - including gdevpdfm.c - where *ppres needs to be initialized to 0.)

(2.B) Let the "surgery" as-is (with the rectification about
pdev->accumulating_substream_resource I mentioned).

Please take a decision on this.


>
> 3. Please note that recently I defined pdf_forget_resource (see
> http://www.ghostscript.com/pipermail/gs-cvs/2004-November/004992.html),
> which may be useful for your code.
> ...

OK, it seems I can simply replace pdf_cancel_resource() with this one
(except it returns void, not a "code").


> 4. It would be useful to group (factor out)
> the call to pdf_enter_substream
> and pdev->substream_Resources = cos_dict_alloc(...)
> into a special local function pdf_enter_BP
> (Well, I'm not in favor with the name pdf_enter_BP,
> fell free to improve it). The purposes are :
> 4.1. do not distribute redundant specifics of BP through GS code;
> 4.2. Simplify the view of the big operator "switch" you introduced;

OK. For the name, I'll choose "pdf_enter_XObject" (being used not only for
/BP, but for /PS too), unless you have another preference.

> 4.3. Move /* Have no better switch*/ to a single place.

While writing the new pdf_enter_XObject(), I noticed an unused parameter of
start_XObject(). It looks we do have a better choice: the "compress" option
passed from the caller. I'll use this, unless you find a reason not to. It
is set by the caller to pdev->CompressPages, not pdev->CompressFonts, which
looks more appropriate; and anyway it's a good idea to let the caller decide
on compression. If this change is not OK with you, it's the moment to say
so.


> 5. You coded :
>
> +           if (!(oper &PDF_NAMECOLLISION_NONAME))
> +               code = cos_dict_put(pdev->local_named_objects,
> objname->data,
> +                                   objname->size,
cos_object_value(&value,
> pres->object));
> +           else
> +               DO_NOTHING;
> +           if (code < 0)
> +               return code;
> ...

Stupid mistake, sorry.


Sincerely yours,
SaGS