+@node Format Conversion Piecemeal
+@subsection Piecemeal Specification
+
+ In contrast to the round-trip specification described in the previous
+subsection (@pxref{Format Conversion Round-Trip}), you can use the variables
+@code{after-insert-file-functions} and @code{write-region-annotate-functions}
+to separately control the respective reading and writing conversions.
+
+ Conversion starts with one representation and produces another
+representation. When there is only one conversion to do, there is no
+conflict about what to start with. However, when there are multiple
+conversions involved, conflict may arise when two conversions need to
+start with the same data.
+
+ This situation is best understood in the context of converting text
+properties during @code{write-region}. For example, the character at
+position 42 in a buffer is @samp{X} with a text property @code{foo}. If
+the conversion for @code{foo} is done by inserting into the buffer, say,
+@samp{FOO:}, then that changes the character at position 42 from
+@samp{X} to @samp{F}. The next conversion will start with the wrong
+data straight away.
+
+ To avoid conflict, cooperative conversions do not modify the buffer,
+but instead specify @dfn{annotations}, a list of elements of the form
+@code{(@var{position} . @var{string})}, sorted in order of increasing
+@var{position}.
+
+ If there is more than one conversion, @code{write-region} merges their
+annotations destructively into one sorted list. Later, when the text
+from the buffer is actually written to the file, it intermixes the
+specified annotations at the corresponding positions. All this takes
+place without modifying the buffer.
+
+@c ??? What about ``overriding'' conversions like those allowed
+@c ??? for `write-region-annotate-functions', below? --ttn
+
+ In contrast, when reading, the annotations intermixed with the text
+are handled immediately. @code{insert-file-contents} sets point to the
+beginning of some text to be converted, then calls the conversion
+functions with the length of that text. These functions should always
+return with point at the beginning of the inserted text. This approach
+makes sense for reading because annotations removed by the first
+converter can't be mistakenly processed by a later converter.
+
+ Each conversion function should scan for the annotations it
+recognizes, remove the annotation, modify the buffer text (to set a text
+property, for example), and return the updated length of the text, as it
+stands after those changes. The value returned by one function becomes
+the argument to the next function.
+
+@defvar write-region-annotate-functions
+A list of functions for @code{write-region} to call. Each function in
+the list is called with two arguments: the start and end of the region
+to be written. These functions should not alter the contents of the
+buffer. Instead, they should return annotations.
+
+@c ??? Following adapted from comment in `build_annotations' (fileio.c).
+@c ??? Perhaps this is intended for internal use only?
+@c ??? Someone who understands this, please reword it. --ttn
+As a special case, if a function returns with a different buffer
+current, Emacs takes it to mean the current buffer contains altered text
+to be output, and discards all previous annotations because they should
+have been dealt with by this function.
+@end defvar
+
+@defvar after-insert-file-functions
+Each function in this list is called by @code{insert-file-contents}
+with one argument, the number of characters inserted, and with point
+at the beginning of the inserted text. Each function should leave
+point unchanged, and return the new character count describing the
+inserted text as modified by the function.
+@c ??? The docstring mentions a handler from `file-name-handler-alist'
+@c "intercepting" `insert-file-contents'. Hmmm. --ttn
+@end defvar
+
+ We invite users to write Lisp programs to store and retrieve text
+properties in files, using these hooks, and thus to experiment with
+various data formats and find good ones. Eventually we hope users
+will produce good, general extensions we can install in Emacs.
+
+ We suggest not trying to handle arbitrary Lisp objects as text property
+names or values---because a program that general is probably difficult
+to write, and slow. Instead, choose a set of possible data types that
+are reasonably flexible, and not too hard to encode.
+