1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-08 10:04:21 +03:00
inform7/docs/inblorb/2-bw.html
2020-03-23 21:42:00 +00:00

879 lines
96 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>1/bp</title>
<meta name="viewport" content="width=device-width initial-scale=1">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Language" content="en-gb">
<link href="../inweb.css" rel="stylesheet" rev="stylesheet" type="text/css">
</head>
<body>
<nav role="navigation">
<h1><a href="../webs.html">Sources</a></h1>
<ul>
<li><a href="../compiler.html">compiler</a></li>
<li><a href="../other.html"><b>other tools</b></a></li>
<li><a href="../extensions.html">extensions and kits</a></li>
<li><a href="../units.html">unit test tools</a></li>
</ul>
<h2>Other Tools</h2>
<ul>
<li><a href="../inblorb/index.html">inblorb</a></li>
<li><a href="../indoc/index.html">indoc</a></li>
<li><a href="../inpolicy/index.html">inpolicy</a></li>
<li><a href="../inrtps/index.html">inrtps</a></li>
</ul>
<h2>Foundation</h2>
<ul>
<li><a href="../../../inweb/docs/foundation-module/index.html">foundation</a></li>
</ul>
</nav>
<main role="main">
<!--Weave of '2/bw' generated by 7-->
<ul class="crumbs"><li><a href="../webs.html">Source</a></li><li><a href="../other.html">Other Tools</a></li><li><a href="index.html">inblorb</a></li><li><a href="index.html#2">Chapter 2: Blorbs</a></li><li><b>Blorb Writer</b></li></ul><p class="purpose">To write the Blorb file, our main output, to disc.</p>
<ul class="toc"><li><a href="#SP1">&#167;1. Blorbs</a></li><li><a href="#SP6">&#167;6. Big-endian integers</a></li><li><a href="#SP7">&#167;7. Chunks</a></li><li><a href="#SP9">&#167;9. Our choice of chunks</a></li><li><a href="#SP24">&#167;24. Main construction</a></li></ul><hr class="tocbar">
<p class="inwebparagraph"><a id="SP1"></a><b>&#167;1. Blorbs. </b>"Blorb" is an IF-specific format, but it is defined as a form of IFF file.
IFF, "Interchange File Format", is a general-purpose wrapper format dating back
to the mid-1980s; it was designed as a way to gather together audiovisual media
for use on home computers. (Though Electronic Arts among others used IFF files
to wrap up entertainment material, Infocom, the pioneer of IF at the time, did
not.) Each IFF file consists of a chunk, but any chunk can contain other
chunks in turn. Chunks are identified with initial ID texts four characters
long. In different domains of computing, people use different chunks, and this
makes different sorts of IFF file look like different file formats to the end
user. So we have TIFF for images, AIFF for uncompressed audio, AVI for movies,
GIF for bitmap graphics, and so on.
</p>
<p class="inwebparagraph"><a id="SP2"></a><b>&#167;2. </b>Main variables:
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">total_size_of_Blorb_chunks</span><span class="plain"> = 0; </span> <span class="comment">ditto, but not counting the <code class="display"><span class="extract">FORM</span></code> header or the <code class="display"><span class="extract">RIdx</span></code> chunk</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">no_indexed_chunks</span><span class="plain"> = 0;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP3"></a><b>&#167;3. </b>As we shall see, chunks can be used for everything from a few words of
copyright text to 100MB of uncompressed choral music.
</p>
<p class="inwebparagraph">Our IFF file will consist of a front part and then the chunks, one after
another, in order of their creation. Every chunk has a type, a 4-character ID
like <code class="display"><span class="extract">"AUTH"</span></code> or <code class="display"><span class="extract">"JPEG"</span></code>, specifying what kind of data it holds; some
chunks are also given resource", " numbers which allow the story file to refer
to them as it runs &mdash; the pictures, sound effects and the story file itself
all have unique resource numbers. (These are called "indexed", because
references to them appear in a special <code class="display"><span class="extract">RIdx</span></code> record in the front part
of the file &mdash; the "resource index".)
</p>
<pre class="definitions">
<span class="definitionkeyword">define</span> <span class="constant">MAX_CHUNK_DATA_STORED_IN_MEMORY</span><span class="plain"> </span><span class="constant">MAX_FILENAME_LENGTH</span>
</pre>
<pre class="display">
<span class="reserved">typedef</span><span class="plain"> </span><span class="reserved">struct</span><span class="plain"> </span><span class="reserved">chunk_metadata</span><span class="plain"> {</span>
<span class="reserved">struct</span><span class="plain"> </span><span class="reserved">filename</span><span class="plain"> *</span><span class="identifier">chunk_file</span><span class="plain">; </span> <span class="comment">if the content is stored on disc</span>
<span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">char</span><span class="plain"> </span><span class="identifier">data_in_memory</span><span class="plain">[</span><span class="constant">MAX_CHUNK_DATA_STORED_IN_MEMORY</span><span class="plain">]; </span> <span class="comment">if the content is stored in memory</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">length_of_data_in_memory</span><span class="plain">; </span> <span class="comment">in bytes; or -1 if the content is stored on disc</span>
<span class="reserved">char</span><span class="plain"> *</span><span class="identifier">chunk_type</span><span class="plain">; </span> <span class="comment">pointer to a 4-character string</span>
<span class="reserved">char</span><span class="plain"> *</span><span class="identifier">index_entry</span><span class="plain">; </span> <span class="comment">ditto</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">resource_id</span><span class="plain">; </span> <span class="comment">meaningful only if this is a chunk which is indexed</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">byte_offset</span><span class="plain">; </span> <span class="comment">from the start of the chunks, which is not quite the start of the IFF file</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">size</span><span class="plain">; </span> <span class="comment">in bytes</span>
<span class="constant">MEMORY_MANAGEMENT</span>
<span class="plain">} </span><span class="reserved">chunk_metadata</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The structure chunk_metadata is private to this section.</p>
<p class="inwebparagraph"><a id="SP4"></a><b>&#167;4. </b>It is not legal to have two or more Snd resources with the same number. The
same goes for Pict resources. These two linked lists are used to store all the
resource numbers encountered.
</p>
<pre class="display">
<span class="reserved">typedef</span><span class="plain"> </span><span class="reserved">struct</span><span class="plain"> </span><span class="reserved">resource_number</span><span class="plain"> {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">num</span><span class="plain">;</span>
<span class="constant">MEMORY_MANAGEMENT</span>
<span class="plain">} </span><span class="reserved">resource_number</span><span class="plain">;</span>
<span class="reserved">linked_list</span><span class="plain"> *</span><span class="identifier">sound_resource</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span> <span class="comment">of <code class="display"><span class="extract">resource_number</span></code></span>
<span class="reserved">linked_list</span><span class="plain"> *</span><span class="identifier">pict_resource</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">; </span> <span class="comment">of <code class="display"><span class="extract">resource_number</span></code></span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The structure resource_number is private to this section.</p>
<p class="inwebparagraph"><a id="SP5"></a><b>&#167;5. </b>And this is used to record alt-descriptions of resources, for the benefit
of partially sighted or deaf users:
</p>
<pre class="display">
<span class="reserved">typedef</span><span class="plain"> </span><span class="reserved">struct</span><span class="plain"> </span><span class="reserved">rdes_record</span><span class="plain"> {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">usage</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">resource_id</span><span class="plain">;</span>
<span class="reserved">char</span><span class="plain"> *</span><span class="identifier">description</span><span class="plain">;</span>
<span class="constant">MEMORY_MANAGEMENT</span>
<span class="plain">} </span><span class="reserved">rdes_record</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The structure rdes_record is accessed in 3/laaf and here.</p>
<p class="inwebparagraph"><a id="SP6"></a><b>&#167;6. Big-endian integers. </b>IFF files use big-endian integers, whereas Inblorb might or might not
(depending on the platform it runs on), so we need routines to write
32, 16 or 8-bit values in explicitly big-endian form:
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Writer::four_word</span><span class="plain">(</span><span class="reserved">FILE</span><span class="plain"> *</span><span class="identifier">F</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">n</span><span class="plain">) {</span>
<span class="identifier">fputc</span><span class="plain">((</span><span class="identifier">n</span><span class="plain"> / 0</span><span class="identifier">x1000000</span><span class="plain">)%0</span><span class="identifier">x100</span><span class="plain">, </span><span class="identifier">F</span><span class="plain">);</span>
<span class="identifier">fputc</span><span class="plain">((</span><span class="identifier">n</span><span class="plain"> / 0</span><span class="identifier">x10000</span><span class="plain">)%0</span><span class="identifier">x100</span><span class="plain">, </span><span class="identifier">F</span><span class="plain">);</span>
<span class="identifier">fputc</span><span class="plain">((</span><span class="identifier">n</span><span class="plain"> / 0</span><span class="identifier">x100</span><span class="plain">)%0</span><span class="identifier">x100</span><span class="plain">, </span><span class="identifier">F</span><span class="plain">);</span>
<span class="identifier">fputc</span><span class="plain">((</span><span class="identifier">n</span><span class="plain">)%0</span><span class="identifier">x100</span><span class="plain">, </span><span class="identifier">F</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Writer::two_word</span><span class="plain">(</span><span class="reserved">FILE</span><span class="plain"> *</span><span class="identifier">F</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">n</span><span class="plain">) {</span>
<span class="identifier">fputc</span><span class="plain">((</span><span class="identifier">n</span><span class="plain"> / 0</span><span class="identifier">x100</span><span class="plain">)%0</span><span class="identifier">x100</span><span class="plain">, </span><span class="identifier">F</span><span class="plain">);</span>
<span class="identifier">fputc</span><span class="plain">((</span><span class="identifier">n</span><span class="plain">)%0</span><span class="identifier">x100</span><span class="plain">, </span><span class="identifier">F</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Writer::one_byte</span><span class="plain">(</span><span class="reserved">FILE</span><span class="plain"> *</span><span class="identifier">F</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">n</span><span class="plain">) {</span>
<span class="identifier">fputc</span><span class="plain">((</span><span class="identifier">n</span><span class="plain">)%0</span><span class="identifier">x100</span><span class="plain">, </span><span class="identifier">F</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Writer::s_four_word</span><span class="plain">(</span><span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">F</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">n</span><span class="plain">) {</span>
<span class="identifier">F</span><span class="plain">[0] = (</span><span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">char</span><span class="plain">) (</span><span class="identifier">n</span><span class="plain"> / 0</span><span class="identifier">x1000000</span><span class="plain">)%0</span><span class="identifier">x100</span><span class="plain">;</span>
<span class="identifier">F</span><span class="plain">[1] = (</span><span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">char</span><span class="plain">) (</span><span class="identifier">n</span><span class="plain"> / 0</span><span class="identifier">x10000</span><span class="plain">)%0</span><span class="identifier">x100</span><span class="plain">;</span>
<span class="identifier">F</span><span class="plain">[2] = (</span><span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">char</span><span class="plain">) (</span><span class="identifier">n</span><span class="plain"> / 0</span><span class="identifier">x100</span><span class="plain">)%0</span><span class="identifier">x100</span><span class="plain">;</span>
<span class="identifier">F</span><span class="plain">[3] = (</span><span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">char</span><span class="plain">) (</span><span class="identifier">n</span><span class="plain">)%0</span><span class="identifier">x100</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Writer::s_two_word</span><span class="plain">(</span><span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">F</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">n</span><span class="plain">) {</span>
<span class="identifier">F</span><span class="plain">[0] = (</span><span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">char</span><span class="plain">) (</span><span class="identifier">n</span><span class="plain"> / 0</span><span class="identifier">x100</span><span class="plain">)%0</span><span class="identifier">x100</span><span class="plain">;</span>
<span class="identifier">F</span><span class="plain">[1] = (</span><span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">char</span><span class="plain">) (</span><span class="identifier">n</span><span class="plain">)%0</span><span class="identifier">x100</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Writer::s_one_byte</span><span class="plain">(</span><span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">F</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">n</span><span class="plain">) {</span>
<span class="identifier">F</span><span class="plain">[0] = (</span><span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">char</span><span class="plain">) (</span><span class="identifier">n</span><span class="plain">)%0</span><span class="identifier">x100</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Writer::four_word is used in <a href="#SP24_2">&#167;24.2</a>, <a href="#SP24_3">&#167;24.3</a>.</p>
<p class="endnote">The function Writer::two_word appears nowhere else.</p>
<p class="endnote">The function Writer::one_byte is used in <a href="#SP24_3">&#167;24.3</a>, <a href="#SP24_3_1">&#167;24.3.1</a>, <a href="#SP24_3_2">&#167;24.3.2</a>.</p>
<p class="endnote">The function Writer::s_four_word is used in <a href="#SP15">&#167;15</a>, <a href="#SP21">&#167;21</a>.</p>
<p class="endnote">The function Writer::s_two_word is used in <a href="#SP16">&#167;16</a>.</p>
<p class="endnote">The function Writer::s_one_byte appears nowhere else.</p>
<p class="inwebparagraph"><a id="SP7"></a><b>&#167;7. Chunks. </b>Although chunks can be written in a nested way &mdash; that's the whole point
of IFF, in fact &mdash; we will always be writing a very flat structure, in
which a single enclosing chunk (<code class="display"><span class="extract">FORM</span></code>) contains a sequence of chunks
with no further chunks inside.
</p>
<pre class="display">
<span class="reserved">chunk_metadata</span><span class="plain"> *</span><span class="identifier">current_chunk</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP8"></a><b>&#167;8. </b>Each chunk is "added" in one of two ways. Either we supply a filename
for an existing binary file on disc which will hold the data we want to
write, or we supply a <code class="display"><span class="extract">NULL</span></code> filename and a <code class="display"><span class="extract">data</span></code> pointer to <code class="display"><span class="extract">length</span></code>
bytes in memory.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Writer::add_chunk_to_blorb</span><span class="plain">(</span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">id</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">resource_num</span><span class="plain">, </span><span class="reserved">filename</span><span class="plain"> *</span><span class="identifier">supplied_filename</span><span class="plain">, </span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">index</span><span class="plain">,</span>
<span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">data</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">length</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Writer::chunk_type_is_legal</span><span class="plain">(</span><span class="identifier">id</span><span class="plain">) == </span><span class="constant">FALSE</span><span class="plain">)</span>
<span class="functiontext">BlorbErrors::fatal</span><span class="plain">(</span><span class="string">"tried to complete non-Blorb chunk"</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Writer::index_entry_is_legal</span><span class="plain">(</span><span class="identifier">index</span><span class="plain">) == </span><span class="constant">FALSE</span><span class="plain">)</span>
<span class="functiontext">BlorbErrors::fatal</span><span class="plain">(</span><span class="string">"tried to include mis-indexed chunk"</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">length</span><span class="plain"> &gt;= </span><span class="constant">MAX_CHUNK_DATA_STORED_IN_MEMORY</span><span class="plain">)</span>
<span class="functiontext">BlorbErrors::fatal</span><span class="plain">(</span><span class="string">"too much chunk data stored in memory"</span><span class="plain">);</span>
<span class="identifier">current_chunk</span><span class="plain"> = </span><span class="identifier">CREATE</span><span class="plain">(</span><span class="reserved">chunk_metadata</span><span class="plain">);</span>
&lt;<span class="cwebmacro">Set the filename for the new chunk</span> <span class="cwebmacronumber">8.1</span>&gt;<span class="plain">;</span>
<span class="identifier">current_chunk</span><span class="plain">-</span><span class="element">&gt;chunk_type</span><span class="plain"> = </span><span class="identifier">id</span><span class="plain">;</span>
<span class="identifier">current_chunk</span><span class="plain">-</span><span class="element">&gt;index_entry</span><span class="plain"> = </span><span class="identifier">index</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">current_chunk</span><span class="plain">-</span><span class="element">&gt;index_entry</span><span class="plain">) </span><span class="identifier">no_indexed_chunks</span><span class="plain">++;</span>
<span class="identifier">current_chunk</span><span class="plain">-</span><span class="element">&gt;byte_offset</span><span class="plain"> = </span><span class="identifier">total_size_of_Blorb_chunks</span><span class="plain">;</span>
<span class="identifier">current_chunk</span><span class="plain">-</span><span class="element">&gt;resource_id</span><span class="plain"> = </span><span class="identifier">resource_num</span><span class="plain">;</span>
&lt;<span class="cwebmacro">Compute the size in bytes of the chunk</span> <span class="cwebmacronumber">8.2</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Advance the total chunk size</span> <span class="cwebmacronumber">8.3</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">verbose_mode</span><span class="plain">)</span>
<span class="identifier">PRINT</span><span class="plain">(</span><span class="string">"! Begun chunk %s: fn is &lt;%f&gt; (innate size %d)\</span><span class="plain">n</span><span class="string">"</span><span class="plain">,</span>
<span class="identifier">current_chunk</span><span class="plain">-</span><span class="element">&gt;chunk_type</span><span class="plain">, </span><span class="identifier">current_chunk</span><span class="plain">-</span><span class="element">&gt;chunk_file</span><span class="plain">, </span><span class="identifier">current_chunk</span><span class="plain">-</span><span class="element">&gt;size</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Writer::add_chunk_to_blorb is used in <a href="#SP13">&#167;13</a>, <a href="#SP14">&#167;14</a>, <a href="#SP15">&#167;15</a>, <a href="#SP16">&#167;16</a>, <a href="#SP17">&#167;17</a>, <a href="#SP19">&#167;19</a>, <a href="#SP21">&#167;21</a>, <a href="#SP22">&#167;22</a>, <a href="#SP23">&#167;23</a>.</p>
<p class="inwebparagraph"><a id="SP8_1"></a><b>&#167;8.1. </b><code class="display">
&lt;<span class="cwebmacrodefn">Set the filename for the new chunk</span> <span class="cwebmacronumber">8.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">data</span><span class="plain">) {</span>
<span class="identifier">current_chunk</span><span class="plain">-</span><span class="element">&gt;chunk_file</span><span class="plain"> = </span><span class="identifier">NULL</span><span class="plain">;</span>
<span class="identifier">current_chunk</span><span class="plain">-</span><span class="element">&gt;length_of_data_in_memory</span><span class="plain"> = </span><span class="identifier">length</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="identifier">length</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++) </span><span class="identifier">current_chunk</span><span class="plain">-</span><span class="element">&gt;data_in_memory</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">] = </span><span class="identifier">data</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">];</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">current_chunk</span><span class="plain">-</span><span class="element">&gt;chunk_file</span><span class="plain"> = </span><span class="identifier">supplied_filename</span><span class="plain">;</span>
<span class="identifier">current_chunk</span><span class="plain">-</span><span class="element">&gt;length_of_data_in_memory</span><span class="plain"> = -1;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP8">&#167;8</a>.</p>
<p class="inwebparagraph"><a id="SP8_2"></a><b>&#167;8.2. </b><code class="display">
&lt;<span class="cwebmacrodefn">Compute the size in bytes of the chunk</span> <span class="cwebmacronumber">8.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">size</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">data</span><span class="plain">) {</span>
<span class="identifier">size</span><span class="plain"> = </span><span class="identifier">length</span><span class="plain">;</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">size</span><span class="plain"> = (</span><span class="reserved">int</span><span class="plain">) </span><span class="functiontext">BinaryFiles::size</span><span class="plain">(</span><span class="identifier">supplied_filename</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Writer::chunk_type_is_already_an_IFF</span><span class="plain">(</span><span class="identifier">current_chunk</span><span class="plain">-</span><span class="element">&gt;chunk_type</span><span class="plain">) == </span><span class="constant">FALSE</span><span class="plain">)</span>
<span class="identifier">size</span><span class="plain"> += 8; </span> <span class="comment">allow 8 further bytes for the chunk header to be added later</span>
<span class="identifier">current_chunk</span><span class="plain">-</span><span class="element">&gt;size</span><span class="plain"> = </span><span class="identifier">size</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP8">&#167;8</a>.</p>
<p class="inwebparagraph"><a id="SP8_3"></a><b>&#167;8.3. </b>Note the adjustment of <code class="display"><span class="extract">total_size_of_Blorb_chunks</span></code> so as to align the next
chunk's position at a two-byte boundary &mdash; this betrays IFF's origin in the
16-bit world of the mid-1980s. Today's formats would likely align at four, eight
or even sixteen-byte boundaries.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Advance the total chunk size</span> <span class="cwebmacronumber">8.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">total_size_of_Blorb_chunks</span><span class="plain"> += </span><span class="identifier">current_chunk</span><span class="plain">-</span><span class="element">&gt;size</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">current_chunk</span><span class="plain">-</span><span class="element">&gt;size</span><span class="plain">) % 2 == 1) </span><span class="identifier">total_size_of_Blorb_chunks</span><span class="plain">++;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP8">&#167;8</a>.</p>
<p class="inwebparagraph"><a id="SP9"></a><b>&#167;9. Our choice of chunks. </b>We will generate only the following chunks with the above apparatus. The full
Blorb specification does include others, but Inform doesn't need them.
</p>
<p class="inwebparagraph">The weasel words "with the above..." are because we will also generate two
chunks separately: the compulsory <code class="display"><span class="extract">"FORM"</span></code> chunk enclosing the entire Blorb, and
an indexing chunk, <code class="display"><span class="extract">"RIdx"</span></code>. Within this index, some chunks appear, but not
others, and they are labelled with the "index entry" text.
</p>
<pre class="display">
<span class="reserved">char</span><span class="plain"> *</span><span class="identifier">legal_Blorb_chunk_types</span><span class="plain">[] = {</span>
<span class="string">"AUTH"</span><span class="plain">, </span><span class="string">"(c) "</span><span class="plain">, </span><span class="string">"Fspc"</span><span class="plain">, </span><span class="string">"RelN"</span><span class="plain">, </span><span class="string">"IFmd"</span><span class="plain">, </span> <span class="comment">miscellaneous identifying data</span>
<span class="string">"JPEG"</span><span class="plain">, </span><span class="string">"PNG "</span><span class="plain">, </span> <span class="comment">images in different formats</span>
<span class="string">"AIFF"</span><span class="plain">, </span><span class="string">"OGGV"</span><span class="plain">, </span><span class="string">"MIDI"</span><span class="plain">, </span><span class="string">"MOD "</span><span class="plain">, </span> <span class="comment">sound effects in different formats</span>
<span class="string">"ZCOD"</span><span class="plain">, </span><span class="string">"GLUL"</span><span class="plain">, </span> <span class="comment">story files in different formats</span>
<span class="string">"RDes"</span><span class="plain">, </span> <span class="comment">resource descriptions (added to the standard in March 2014)</span>
<span class="identifier">NULL</span><span class="plain"> };</span>
<span class="reserved">char</span><span class="plain"> *</span><span class="identifier">legal_Blorb_index_entries</span><span class="plain">[] = {</span>
<span class="string">"Pict"</span><span class="plain">, </span><span class="string">"Snd "</span><span class="plain">, </span><span class="string">"Exec"</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain"> };</span>
</pre>
<p class="inwebparagraph"></p>
<p class="inwebparagraph"><a id="SP10"></a><b>&#167;10. </b>Because we are wisely paranoid:
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Writer::chunk_type_is_legal</span><span class="plain">(</span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">type</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">type</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">FALSE</span><span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">legal_Blorb_chunk_types</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]; </span><span class="identifier">i</span><span class="plain">++)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">strcmp</span><span class="plain">(</span><span class="identifier">type</span><span class="plain">, </span><span class="identifier">legal_Blorb_chunk_types</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]) == 0)</span>
<span class="reserved">return</span><span class="plain"> </span><span class="constant">TRUE</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="constant">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Writer::index_entry_is_legal</span><span class="plain">(</span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">entry</span><span class="plain">) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">entry</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">TRUE</span><span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">legal_Blorb_index_entries</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]; </span><span class="identifier">i</span><span class="plain">++)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">strcmp</span><span class="plain">(</span><span class="identifier">entry</span><span class="plain">, </span><span class="identifier">legal_Blorb_index_entries</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]) == 0)</span>
<span class="reserved">return</span><span class="plain"> </span><span class="constant">TRUE</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="constant">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Writer::chunk_type_is_legal is used in <a href="#SP8">&#167;8</a>.</p>
<p class="endnote">The function Writer::index_entry_is_legal is used in <a href="#SP8">&#167;8</a>.</p>
<p class="inwebparagraph"><a id="SP11"></a><b>&#167;11. </b>This function checks a linked list to see if a resource number is used twice.
If so, TRUE is returned and the rest of the program is expected to immediately
exit with a fatal error. Otherwise, FALSE is returned, indicating that
everything is fine.
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Writer::resource_seen</span><span class="plain">(</span><span class="reserved">linked_list</span><span class="plain"> *</span><span class="identifier">L</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">value</span><span class="plain">) {</span>
<span class="reserved">resource_number</span><span class="plain"> *</span><span class="identifier">rn</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER_LINKED_LIST</span><span class="plain">(</span><span class="identifier">rn</span><span class="plain">, </span><span class="reserved">resource_number</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">rn</span><span class="plain">-</span><span class="element">&gt;num</span><span class="plain"> == </span><span class="identifier">value</span><span class="plain">)</span>
<span class="reserved">return</span><span class="plain"> </span><span class="constant">TRUE</span><span class="plain">;</span>
<span class="identifier">rn</span><span class="plain"> = </span><span class="identifier">CREATE</span><span class="plain">(</span><span class="reserved">resource_number</span><span class="plain">);</span>
<span class="identifier">rn</span><span class="plain">-</span><span class="element">&gt;num</span><span class="plain"> = </span><span class="identifier">value</span><span class="plain">;</span>
<span class="identifier">ADD_TO_LINKED_LIST</span><span class="plain">(</span><span class="identifier">rn</span><span class="plain">, </span><span class="reserved">resource_number</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">);</span>
<span class="reserved">return</span><span class="plain"> </span><span class="constant">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Writer::resource_seen is used in <a href="#SP17">&#167;17</a>, <a href="#SP19">&#167;19</a>.</p>
<p class="inwebparagraph"><a id="SP12"></a><b>&#167;12. </b>Because it will make a difference to how we embed a file into our Blorb,
we need to know whether the chunk in question is already an IFF in its
own right. Only one type of chunk is, as it happens:
</p>
<pre class="display">
<span class="reserved">int</span><span class="plain"> </span><span class="functiontext">Writer::chunk_type_is_already_an_IFF</span><span class="plain">(</span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">type</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">strcmp</span><span class="plain">(</span><span class="identifier">type</span><span class="plain">, </span><span class="string">"AIFF"</span><span class="plain">)==0) </span><span class="reserved">return</span><span class="plain"> </span><span class="constant">TRUE</span><span class="plain">;</span>
<span class="reserved">return</span><span class="plain"> </span><span class="constant">FALSE</span><span class="plain">;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Writer::chunk_type_is_already_an_IFF is used in <a href="#SP8_2">&#167;8.2</a>, <a href="#SP24_3">&#167;24.3</a>.</p>
<p class="inwebparagraph"><a id="SP13"></a><b>&#167;13. </b><code class="display"><span class="extract">"AUTH"</span></code>: author's name, as a null-terminated string.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Writer::author_chunk</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">t</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">verbose_mode</span><span class="plain">) </span><span class="identifier">PRINT</span><span class="plain">(</span><span class="string">"! Author: &lt;%S&gt;\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">t</span><span class="plain">);</span>
<span class="functiontext">Writer::add_chunk_to_blorb</span><span class="plain">(</span><span class="string">"AUTH"</span><span class="plain">, 0, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, (</span><span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">char</span><span class="plain"> *) </span><span class="identifier">t</span><span class="plain">, </span><span class="functiontext">Str::len</span><span class="plain">(</span><span class="identifier">t</span><span class="plain">));</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Writer::author_chunk is used in 1/bp (<a href="1-bp.html#SP7_2">&#167;7.2</a>).</p>
<p class="inwebparagraph"><a id="SP14"></a><b>&#167;14. </b><code class="display"><span class="extract">"(c) "</span></code>: copyright declaration.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Writer::copyright_chunk</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">t</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">verbose_mode</span><span class="plain">) </span><span class="identifier">PRINT</span><span class="plain">(</span><span class="string">"! Copyright declaration: &lt;%S&gt;\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">t</span><span class="plain">);</span>
<span class="functiontext">Writer::add_chunk_to_blorb</span><span class="plain">(</span><span class="string">"(c) "</span><span class="plain">, 0, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, (</span><span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">char</span><span class="plain"> *) </span><span class="identifier">t</span><span class="plain">, </span><span class="functiontext">Str::len</span><span class="plain">(</span><span class="identifier">t</span><span class="plain">));</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Writer::copyright_chunk is used in 1/bp (<a href="1-bp.html#SP7_2">&#167;7.2</a>).</p>
<p class="inwebparagraph"><a id="SP15"></a><b>&#167;15. </b><code class="display"><span class="extract">"Fspc"</span></code>: frontispiece image ID number &mdash; which picture resource provides
cover art, in other words.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Writer::frontispiece_chunk</span><span class="plain">(</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">pn</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">verbose_mode</span><span class="plain">) </span><span class="identifier">PRINT</span><span class="plain">(</span><span class="string">"! Frontispiece is image %d\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">pn</span><span class="plain">);</span>
<span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">char</span><span class="plain"> </span><span class="identifier">data</span><span class="plain">[4];</span>
<span class="functiontext">Writer::s_four_word</span><span class="plain">(</span><span class="identifier">data</span><span class="plain">, </span><span class="identifier">pn</span><span class="plain">);</span>
<span class="functiontext">Writer::add_chunk_to_blorb</span><span class="plain">(</span><span class="string">"Fspc"</span><span class="plain">, 0, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">data</span><span class="plain">, 4);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Writer::frontispiece_chunk is used in 1/bp (<a href="1-bp.html#SP7_2_1">&#167;7.2.1</a>).</p>
<p class="inwebparagraph"><a id="SP16"></a><b>&#167;16. </b><code class="display"><span class="extract">"RelN"</span></code>: release number.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Writer::release_chunk</span><span class="plain">(</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">rn</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">verbose_mode</span><span class="plain">) </span><span class="identifier">PRINT</span><span class="plain">(</span><span class="string">"! Release number is %d\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">rn</span><span class="plain">);</span>
<span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">char</span><span class="plain"> </span><span class="identifier">data</span><span class="plain">[2];</span>
<span class="functiontext">Writer::s_two_word</span><span class="plain">(</span><span class="identifier">data</span><span class="plain">, </span><span class="identifier">rn</span><span class="plain">);</span>
<span class="functiontext">Writer::add_chunk_to_blorb</span><span class="plain">(</span><span class="string">"RelN"</span><span class="plain">, 0, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">data</span><span class="plain">, 2);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Writer::release_chunk is used in 1/bp (<a href="1-bp.html#SP7_2">&#167;7.2</a>).</p>
<p class="inwebparagraph"><a id="SP17"></a><b>&#167;17. </b><code class="display"><span class="extract">"Pict"</span></code>: a picture, or image. This must be available as a binary file on
disc, and in a format which Blorb allows: for Inform 7 use, this will always
be PNG or JPEG. There can be any number of these chunks.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Writer::picture_chunk</span><span class="plain">(</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">n</span><span class="plain">, </span><span class="reserved">filename</span><span class="plain"> *</span><span class="identifier">fn</span><span class="plain">, </span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">alt</span><span class="plain">) {</span>
<span class="reserved">char</span><span class="plain"> *</span><span class="identifier">type</span><span class="plain"> = </span><span class="string">"PNG "</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">form</span><span class="plain"> = </span><span class="functiontext">Filenames::guess_format</span><span class="plain">(</span><span class="identifier">fn</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">form</span><span class="plain"> == </span><span class="constant">FORMAT_PERHAPS_JPEG</span><span class="plain">) </span><span class="identifier">type</span><span class="plain"> = </span><span class="string">"JPEG"</span><span class="plain">;</span>
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">form</span><span class="plain"> == </span><span class="constant">FORMAT_PERHAPS_PNG</span><span class="plain">) </span><span class="identifier">type</span><span class="plain"> = </span><span class="string">"PNG "</span><span class="plain">;</span>
<span class="reserved">else</span><span class="plain"> </span><span class="functiontext">BlorbErrors::error_1f</span><span class="plain">(</span><span class="string">"image file has unknown file extension "</span>
<span class="string">"(expected e.g. '.png' for PNG, '.jpeg' for JPEG)"</span><span class="plain">, </span><span class="identifier">fn</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">n</span><span class="plain"> &lt; 1) </span><span class="functiontext">BlorbErrors::fatal</span><span class="plain">(</span><span class="string">"Picture resource number is less than 1"</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">pict_resource</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">pict_resource</span><span class="plain"> = </span><span class="identifier">NEW_LINKED_LIST</span><span class="plain">(</span><span class="reserved">resource_number</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Writer::resource_seen</span><span class="plain">(</span><span class="identifier">pict_resource</span><span class="plain">, </span><span class="identifier">n</span><span class="plain">))</span>
<span class="functiontext">BlorbErrors::fatal</span><span class="plain">(</span><span class="string">"Duplicate Picture resource number"</span><span class="plain">);</span>
<span class="functiontext">Writer::add_chunk_to_blorb</span><span class="plain">(</span><span class="identifier">type</span><span class="plain">, </span><span class="identifier">n</span><span class="plain">, </span><span class="identifier">fn</span><span class="plain">, </span><span class="string">"Pict"</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, 0);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Str::len</span><span class="plain">(</span><span class="identifier">alt</span><span class="plain">) &gt; 0) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">L</span><span class="plain"> = </span><span class="functiontext">Str::len</span><span class="plain">(</span><span class="identifier">alt</span><span class="plain">)+1;</span>
<span class="reserved">char</span><span class="plain"> *</span><span class="identifier">alt_Cs</span><span class="plain"> = </span><span class="functiontext">Memory::I7_malloc</span><span class="plain">(</span><span class="identifier">L</span><span class="plain">, </span><span class="constant">STRING_STORAGE_MREASON</span><span class="plain">);</span>
<span class="functiontext">Str::copy_to_ISO_string</span><span class="plain">(</span><span class="identifier">alt_Cs</span><span class="plain">, </span><span class="identifier">alt</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">);</span>
<span class="functiontext">Writer::add_rdes_record</span><span class="plain">(1, </span><span class="identifier">n</span><span class="plain">, </span><span class="identifier">alt_Cs</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="identifier">no_pictures_included</span><span class="plain">++;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Writer::picture_chunk is used in <a href="#SP18">&#167;18</a>, 1/bp (<a href="1-bp.html#SP7_2">&#167;7.2</a>).</p>
<p class="inwebparagraph"><a id="SP18"></a><b>&#167;18. </b>For images identified by name. The older Blorb creation program, <code class="display"><span class="extract">perlBlorb</span></code>,
would emit helpful I6 constant declarations, allowing the programmer to
include these an I6 source file and then write, say, <code class="display"><span class="extract">PlaySound(SOUND_Boom)</span></code>
rather than <code class="display"><span class="extract">PlaySound(5)</span></code>. (Whenever the Blurb file is changed, the constants
must be included again.)
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Writer::picture_chunk_text</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">name</span><span class="plain">, </span><span class="reserved">filename</span><span class="plain"> *</span><span class="identifier">F</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Str::len</span><span class="plain">(</span><span class="identifier">name</span><span class="plain">) == 0) {</span>
<span class="identifier">PRINT</span><span class="plain">(</span><span class="string">"! Null picture ID, using %d\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">picture_resource_num</span><span class="plain">);</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">PRINT</span><span class="plain">(</span><span class="string">"Constant PICTURE_%S = %d;\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">name</span><span class="plain">, </span><span class="identifier">picture_resource_num</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="identifier">picture_resource_num</span><span class="plain">++;</span>
<span class="functiontext">Writer::picture_chunk</span><span class="plain">(</span><span class="identifier">picture_resource_num</span><span class="plain">, </span><span class="identifier">F</span><span class="plain">, </span><span class="identifier">I</span><span class="string">""</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Writer::picture_chunk_text is used in 1/bp (<a href="1-bp.html#SP7_2">&#167;7.2</a>).</p>
<p class="inwebparagraph"><a id="SP19"></a><b>&#167;19. </b><code class="display"><span class="extract">"Snd "</span></code>: a sound effect. This must be available as a binary file on
disc, and in a format which Blorb allows: for Inform 7 use, this is officially
Ogg Vorbis or AIFF at present, but there has been repeated discussion about
adding MOD ("SoundTracker") or MIDI files, so both are supported here.
</p>
<p class="inwebparagraph">There can be any number of these chunks, too.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Writer::sound_chunk</span><span class="plain">(</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">n</span><span class="plain">, </span><span class="reserved">filename</span><span class="plain"> *</span><span class="identifier">fn</span><span class="plain">, </span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">alt</span><span class="plain">) {</span>
<span class="reserved">char</span><span class="plain"> *</span><span class="identifier">type</span><span class="plain"> = </span><span class="string">"AIFF"</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">form</span><span class="plain"> = </span><span class="functiontext">Filenames::guess_format</span><span class="plain">(</span><span class="identifier">fn</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">form</span><span class="plain"> == </span><span class="constant">FORMAT_PERHAPS_OGG</span><span class="plain">) </span><span class="identifier">type</span><span class="plain"> = </span><span class="string">"OGGV"</span><span class="plain">;</span>
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">form</span><span class="plain"> == </span><span class="constant">FORMAT_PERHAPS_MIDI</span><span class="plain">) </span><span class="identifier">type</span><span class="plain"> = </span><span class="string">"MIDI"</span><span class="plain">;</span>
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">form</span><span class="plain"> == </span><span class="constant">FORMAT_PERHAPS_MOD</span><span class="plain">) </span><span class="identifier">type</span><span class="plain"> = </span><span class="string">"MOD "</span><span class="plain">;</span>
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">form</span><span class="plain"> == </span><span class="constant">FORMAT_PERHAPS_AIFF</span><span class="plain">) </span><span class="identifier">type</span><span class="plain"> = </span><span class="string">"AIFF"</span><span class="plain">;</span>
<span class="reserved">else</span><span class="plain"> </span><span class="functiontext">BlorbErrors::error_1f</span><span class="plain">(</span><span class="string">"sound file has unknown file extension "</span>
<span class="string">"(expected e.g. '.ogg', '.midi', '.mod' or '.aiff', as appropriate)"</span><span class="plain">, </span><span class="identifier">fn</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">n</span><span class="plain"> &lt; 3) </span><span class="functiontext">BlorbErrors::fatal</span><span class="plain">(</span><span class="string">"Sound resource number is less than 3"</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">sound_resource</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="identifier">sound_resource</span><span class="plain"> = </span><span class="identifier">NEW_LINKED_LIST</span><span class="plain">(</span><span class="reserved">resource_number</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Writer::resource_seen</span><span class="plain">(</span><span class="identifier">sound_resource</span><span class="plain">, </span><span class="identifier">n</span><span class="plain">)) </span><span class="functiontext">BlorbErrors::fatal</span><span class="plain">(</span><span class="string">"Duplicate Sound resource number"</span><span class="plain">);</span>
<span class="functiontext">Writer::add_chunk_to_blorb</span><span class="plain">(</span><span class="identifier">type</span><span class="plain">, </span><span class="identifier">n</span><span class="plain">, </span><span class="identifier">fn</span><span class="plain">, </span><span class="string">"Snd "</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, 0);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Str::len</span><span class="plain">(</span><span class="identifier">alt</span><span class="plain">) &gt; 0) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">L</span><span class="plain"> = </span><span class="functiontext">Str::len</span><span class="plain">(</span><span class="identifier">alt</span><span class="plain">)+1;</span>
<span class="reserved">char</span><span class="plain"> *</span><span class="identifier">alt_Cs</span><span class="plain"> = </span><span class="functiontext">Memory::I7_malloc</span><span class="plain">(</span><span class="identifier">L</span><span class="plain">, </span><span class="constant">STRING_STORAGE_MREASON</span><span class="plain">);</span>
<span class="functiontext">Str::copy_to_ISO_string</span><span class="plain">(</span><span class="identifier">alt_Cs</span><span class="plain">, </span><span class="identifier">alt</span><span class="plain">, </span><span class="identifier">L</span><span class="plain">);</span>
<span class="functiontext">Writer::add_rdes_record</span><span class="plain">(2, </span><span class="identifier">n</span><span class="plain">, </span><span class="identifier">alt_Cs</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="identifier">no_sounds_included</span><span class="plain">++;</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Writer::sound_chunk is used in <a href="#SP20">&#167;20</a>, 1/bp (<a href="1-bp.html#SP7_2">&#167;7.2</a>).</p>
<p class="inwebparagraph"><a id="SP20"></a><b>&#167;20. </b>And again, by name:
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Writer::sound_chunk_text</span><span class="plain">(</span><span class="reserved">text_stream</span><span class="plain"> *</span><span class="identifier">name</span><span class="plain">, </span><span class="reserved">filename</span><span class="plain"> *</span><span class="identifier">F</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Str::len</span><span class="plain">(</span><span class="identifier">name</span><span class="plain">) == 0) {</span>
<span class="identifier">PRINT</span><span class="plain">(</span><span class="string">"! Null sound ID, using %d\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">sound_resource_num</span><span class="plain">);</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">PRINT</span><span class="plain">(</span><span class="string">"Constant SOUND_%S = %d;\</span><span class="plain">n</span><span class="string">"</span><span class="plain">, </span><span class="identifier">name</span><span class="plain">, </span><span class="identifier">sound_resource_num</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="identifier">sound_resource_num</span><span class="plain">++;</span>
<span class="functiontext">Writer::sound_chunk</span><span class="plain">(</span><span class="identifier">sound_resource_num</span><span class="plain">, </span><span class="identifier">F</span><span class="plain">, </span><span class="identifier">I</span><span class="string">""</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Writer::sound_chunk_text is used in 1/bp (<a href="1-bp.html#SP7_2">&#167;7.2</a>).</p>
<p class="inwebparagraph"><a id="SP21"></a><b>&#167;21. </b><code class="display"><span class="extract">"RDes"</span></code>: the resource description, a repository for alt-texts describing
images or sounds.
</p>
<pre class="display">
<span class="identifier">size_t</span><span class="plain"> </span><span class="identifier">size_of_rdes_chunk</span><span class="plain"> = 0;</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Writer::add_rdes_record</span><span class="plain">(</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">usage</span><span class="plain">, </span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">n</span><span class="plain">, </span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">alt</span><span class="plain">) {</span>
<span class="reserved">rdes_record</span><span class="plain"> *</span><span class="identifier">rr</span><span class="plain"> = </span><span class="identifier">CREATE</span><span class="plain">(</span><span class="reserved">rdes_record</span><span class="plain">);</span>
<span class="identifier">rr</span><span class="plain">-</span><span class="element">&gt;usage</span><span class="plain"> = </span><span class="identifier">usage</span><span class="plain">;</span>
<span class="identifier">rr</span><span class="plain">-</span><span class="element">&gt;resource_id</span><span class="plain"> = </span><span class="identifier">n</span><span class="plain">;</span>
<span class="identifier">rr</span><span class="plain">-</span><span class="element">&gt;description</span><span class="plain"> = </span><span class="functiontext">Memory::new_string</span><span class="plain">(</span><span class="identifier">alt</span><span class="plain">);</span>
<span class="identifier">size_of_rdes_chunk</span><span class="plain"> += 12 + (</span><span class="identifier">size_t</span><span class="plain">) </span><span class="identifier">strlen</span><span class="plain">(</span><span class="identifier">alt</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Writer::rdes_chunk</span><span class="plain">(</span><span class="reserved">void</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">size_of_rdes_chunk</span><span class="plain"> &gt; 0) {</span>
<span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">char</span><span class="plain"> *</span><span class="identifier">rdes_data</span><span class="plain"> =</span>
<span class="plain">(</span><span class="reserved">unsigned</span><span class="plain"> </span><span class="reserved">char</span><span class="plain"> *) </span><span class="functiontext">Memory::I7_malloc</span><span class="plain">((</span><span class="reserved">int</span><span class="plain">) </span><span class="identifier">size_of_rdes_chunk</span><span class="plain"> + 9, </span><span class="constant">RDES_MREASON</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">rdes_data</span><span class="plain"> == </span><span class="identifier">NULL</span><span class="plain">) </span><span class="functiontext">BlorbErrors::fatal</span><span class="plain">(</span><span class="string">"Run out of memory"</span><span class="plain">);</span>
<span class="identifier">size_t</span><span class="plain"> </span><span class="identifier">pos</span><span class="plain"> = 4;</span>
<span class="functiontext">Writer::s_four_word</span><span class="plain">(</span><span class="identifier">rdes_data</span><span class="plain">, </span><span class="identifier">NUMBER_CREATED</span><span class="plain">(</span><span class="reserved">rdes_record</span><span class="plain">));</span>
<span class="reserved">rdes_record</span><span class="plain"> *</span><span class="identifier">rr</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">rr</span><span class="plain">, </span><span class="reserved">rdes_record</span><span class="plain">) {</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">rr</span><span class="plain">-</span><span class="element">&gt;usage</span><span class="plain"> == 1) </span><span class="identifier">strcpy</span><span class="plain">((</span><span class="reserved">char</span><span class="plain"> *) (</span><span class="identifier">rdes_data</span><span class="plain"> + </span><span class="identifier">pos</span><span class="plain">), </span><span class="string">"Pict"</span><span class="plain">);</span>
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">rr</span><span class="plain">-</span><span class="element">&gt;usage</span><span class="plain"> == 2) </span><span class="identifier">strcpy</span><span class="plain">((</span><span class="reserved">char</span><span class="plain"> *) (</span><span class="identifier">rdes_data</span><span class="plain"> + </span><span class="identifier">pos</span><span class="plain">), </span><span class="string">"Snd "</span><span class="plain">);</span>
<span class="reserved">else</span><span class="plain"> </span><span class="functiontext">Writer::s_four_word</span><span class="plain">(</span><span class="identifier">rdes_data</span><span class="plain"> + </span><span class="identifier">pos</span><span class="plain">, 0);</span>
<span class="functiontext">Writer::s_four_word</span><span class="plain">(</span><span class="identifier">rdes_data</span><span class="plain"> + </span><span class="identifier">pos</span><span class="plain"> + 4, </span><span class="identifier">rr</span><span class="plain">-</span><span class="element">&gt;resource_id</span><span class="plain">);</span>
<span class="functiontext">Writer::s_four_word</span><span class="plain">(</span><span class="identifier">rdes_data</span><span class="plain"> + </span><span class="identifier">pos</span><span class="plain"> + 8, (</span><span class="reserved">int</span><span class="plain">) </span><span class="identifier">strlen</span><span class="plain">(</span><span class="identifier">rr</span><span class="plain">-</span><span class="element">&gt;description</span><span class="plain">));</span>
<span class="identifier">strcpy</span><span class="plain">((</span><span class="reserved">char</span><span class="plain"> *) (</span><span class="identifier">rdes_data</span><span class="plain"> + </span><span class="identifier">pos</span><span class="plain"> + 12), </span><span class="identifier">rr</span><span class="plain">-</span><span class="element">&gt;description</span><span class="plain">);</span>
<span class="identifier">pos</span><span class="plain"> += 12 + (</span><span class="identifier">size_t</span><span class="plain">) </span><span class="identifier">strlen</span><span class="plain">(</span><span class="identifier">rr</span><span class="plain">-</span><span class="element">&gt;description</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">pos</span><span class="plain"> != </span><span class="identifier">size_of_rdes_chunk</span><span class="plain"> + 4) </span><span class="functiontext">BlorbErrors::fatal</span><span class="plain">(</span><span class="string">"misconstructed rdes"</span><span class="plain">);</span>
<span class="functiontext">Writer::add_chunk_to_blorb</span><span class="plain">(</span><span class="string">"RDes"</span><span class="plain">, 0, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">rdes_data</span><span class="plain">, (</span><span class="reserved">int</span><span class="plain">) </span><span class="identifier">pos</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Writer::add_rdes_record is used in <a href="#SP17">&#167;17</a>, <a href="#SP19">&#167;19</a>.</p>
<p class="endnote">The function Writer::rdes_chunk is used in <a href="#SP24">&#167;24</a>.</p>
<p class="inwebparagraph"><a id="SP22"></a><b>&#167;22. </b><code class="display"><span class="extract">"Exec"</span></code>: the executable program, which will normally be a Z-machine or
Glulx story file. It's legal to make a blorb with no story file in, but
Inform 7 never does this.
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Writer::executable_chunk</span><span class="plain">(</span><span class="reserved">filename</span><span class="plain"> *</span><span class="identifier">fn</span><span class="plain">) {</span>
<span class="reserved">char</span><span class="plain"> *</span><span class="identifier">type</span><span class="plain"> = </span><span class="string">"ZCOD"</span><span class="plain">;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">form</span><span class="plain"> = </span><span class="functiontext">Filenames::guess_format</span><span class="plain">(</span><span class="identifier">fn</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">form</span><span class="plain"> == </span><span class="constant">FORMAT_PERHAPS_GLULX</span><span class="plain">) </span><span class="identifier">type</span><span class="plain"> = </span><span class="string">"GLUL"</span><span class="plain">;</span>
<span class="reserved">else</span><span class="plain"> </span><span class="reserved">if</span><span class="plain"> (</span><span class="identifier">form</span><span class="plain"> == </span><span class="constant">FORMAT_PERHAPS_ZCODE</span><span class="plain">) </span><span class="identifier">type</span><span class="plain"> = </span><span class="string">"ZCOD"</span><span class="plain">;</span>
<span class="reserved">else</span><span class="plain"> </span><span class="functiontext">BlorbErrors::error_1f</span><span class="plain">(</span><span class="string">"story file has unknown file extension "</span>
<span class="string">"(expected e.g. '.z5' for Z-code, '.ulx' for Glulx)"</span><span class="plain">, </span><span class="identifier">fn</span><span class="plain">);</span>
<span class="functiontext">Writer::add_chunk_to_blorb</span><span class="plain">(</span><span class="identifier">type</span><span class="plain">, 0, </span><span class="identifier">fn</span><span class="plain">, </span><span class="string">"Exec"</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, 0);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Writer::executable_chunk is used in 1/bp (<a href="1-bp.html#SP7_2">&#167;7.2</a>).</p>
<p class="inwebparagraph"><a id="SP23"></a><b>&#167;23. </b><code class="display"><span class="extract">"IFmd"</span></code>: the bibliographic data (or "metadata") about the work of IF
being blorbed up, in the form of an iFiction record. (The format of which
is set out in the "Treaty of Babel" agreement.)
</p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Writer::metadata_chunk</span><span class="plain">(</span><span class="reserved">filename</span><span class="plain"> *</span><span class="identifier">fn</span><span class="plain">) {</span>
<span class="functiontext">Writer::add_chunk_to_blorb</span><span class="plain">(</span><span class="string">"IFmd"</span><span class="plain">, 0, </span><span class="identifier">fn</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, </span><span class="identifier">NULL</span><span class="plain">, 0);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Writer::metadata_chunk is used in 1/bp (<a href="1-bp.html#SP7_2">&#167;7.2</a>).</p>
<p class="inwebparagraph"><a id="SP24"></a><b>&#167;24. Main construction. </b></p>
<pre class="display">
<span class="reserved">void</span><span class="plain"> </span><span class="functiontext">Writer::write_blorb_file</span><span class="plain">(</span><span class="reserved">filename</span><span class="plain"> *</span><span class="identifier">out</span><span class="plain">) {</span>
<span class="functiontext">Writer::rdes_chunk</span><span class="plain">();</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">NUMBER_CREATED</span><span class="plain">(</span><span class="reserved">chunk_metadata</span><span class="plain">) == 0) </span><span class="reserved">return</span><span class="plain">;</span>
<span class="reserved">FILE</span><span class="plain"> *</span><span class="identifier">IFF</span><span class="plain"> = </span><span class="functiontext">BinaryFiles::open_for_writing</span><span class="plain">(</span><span class="identifier">out</span><span class="plain">);</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">RIdx_size</span><span class="plain">, </span><span class="identifier">first_byte_after_index</span><span class="plain">;</span>
&lt;<span class="cwebmacro">Calculate the sizes of the whole file and the index chunk</span> <span class="cwebmacronumber">24.1</span>&gt;<span class="plain">;</span>
&lt;<span class="cwebmacro">Write the initial FORM chunk of the IFF file, and then the index</span> <span class="cwebmacronumber">24.2</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">verbose_mode</span><span class="plain">) </span>&lt;<span class="cwebmacro">Print out a copy of the chunk table</span> <span class="cwebmacronumber">24.4</span>&gt;<span class="plain">;</span>
<span class="reserved">chunk_metadata</span><span class="plain"> *</span><span class="identifier">chunk</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">chunk</span><span class="plain">, </span><span class="reserved">chunk_metadata</span><span class="plain">) </span>&lt;<span class="cwebmacro">Write the chunk</span> <span class="cwebmacronumber">24.3</span>&gt;<span class="plain">;</span>
<span class="functiontext">BinaryFiles::close</span><span class="plain">(</span><span class="identifier">IFF</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">The function Writer::write_blorb_file is used in 1/mn (<a href="1-mn.html#SP3">&#167;3</a>).</p>
<p class="inwebparagraph"><a id="SP24_1"></a><b>&#167;24.1. </b>The bane of IFF file generation is that each chunk has to be marked
up-front with an offset to skip past it. This means that, unlike with XML
or other files having flexible-sized ingredients delimited by begin-end
markers, we always have to know the length of a chunk before we start
writing it.
</p>
<p class="inwebparagraph">That even extends to the file itself, which is a single IFF chunk of type
<code class="display"><span class="extract">"FORM"</span></code>. So we need to think carefully. We will need the <code class="display"><span class="extract">FORM</span></code> header,
then the header for the <code class="display"><span class="extract">RIdx</span></code> indexing chunk, then the body of that indexing
chunk &mdash; with one record for each indexed chunk; and then room for all of
the chunks we'll copy in, whether they are indexed or not.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Calculate the sizes of the whole file and the index chunk</span> <span class="cwebmacronumber">24.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">FORM_header_size</span><span class="plain"> = 12;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">RIdx_header_size</span><span class="plain"> = 12;</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">index_entry_size</span><span class="plain"> = 12;</span>
<span class="identifier">RIdx_size</span><span class="plain"> = </span><span class="identifier">RIdx_header_size</span><span class="plain"> + </span><span class="identifier">index_entry_size</span><span class="plain">*</span><span class="identifier">no_indexed_chunks</span><span class="plain">;</span>
<span class="identifier">first_byte_after_index</span><span class="plain"> = </span><span class="identifier">FORM_header_size</span><span class="plain"> + </span><span class="identifier">RIdx_size</span><span class="plain">;</span>
<span class="identifier">blorb_file_size</span><span class="plain"> = </span><span class="identifier">first_byte_after_index</span><span class="plain"> + </span><span class="identifier">total_size_of_Blorb_chunks</span><span class="plain">;</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP24">&#167;24</a>.</p>
<p class="inwebparagraph"><a id="SP24_2"></a><b>&#167;24.2. </b>Each different IFF file format is supposed to provide its own "magic text"
identifying what the file format is, and for Blorbs that text is "IFRS",
short for "IF Resource".
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Write the initial FORM chunk of the IFF file, and then the index</span> <span class="cwebmacronumber">24.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">fprintf</span><span class="plain">(</span><span class="identifier">IFF</span><span class="plain">, </span><span class="string">"FORM"</span><span class="plain">);</span>
<span class="functiontext">Writer::four_word</span><span class="plain">(</span><span class="identifier">IFF</span><span class="plain">, </span><span class="identifier">blorb_file_size</span><span class="plain"> - 8); </span> <span class="comment">offset to end of <code class="display"><span class="extract">FORM</span></code> after the 8 bytes so far</span>
<span class="identifier">fprintf</span><span class="plain">(</span><span class="identifier">IFF</span><span class="plain">, </span><span class="string">"IFRS"</span><span class="plain">); </span> <span class="comment">magic text identifying the IFF as a Blorb</span>
<span class="identifier">fprintf</span><span class="plain">(</span><span class="identifier">IFF</span><span class="plain">, </span><span class="string">"RIdx"</span><span class="plain">);</span>
<span class="functiontext">Writer::four_word</span><span class="plain">(</span><span class="identifier">IFF</span><span class="plain">, </span><span class="identifier">RIdx_size</span><span class="plain"> - 8); </span> <span class="comment">offset to end of <code class="display"><span class="extract">RIdx</span></code> after the 8 bytes so far</span>
<span class="functiontext">Writer::four_word</span><span class="plain">(</span><span class="identifier">IFF</span><span class="plain">, </span><span class="identifier">no_indexed_chunks</span><span class="plain">); </span> <span class="comment">i.e., number of entries in the index</span>
<span class="reserved">chunk_metadata</span><span class="plain"> *</span><span class="identifier">chunk</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">chunk</span><span class="plain">, </span><span class="reserved">chunk_metadata</span><span class="plain">)</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">chunk</span><span class="plain">-</span><span class="element">&gt;index_entry</span><span class="plain">) {</span>
<span class="identifier">fprintf</span><span class="plain">(</span><span class="identifier">IFF</span><span class="plain">, </span><span class="string">"%s"</span><span class="plain">, </span><span class="identifier">chunk</span><span class="plain">-</span><span class="element">&gt;index_entry</span><span class="plain">);</span>
<span class="functiontext">Writer::four_word</span><span class="plain">(</span><span class="identifier">IFF</span><span class="plain">, </span><span class="identifier">chunk</span><span class="plain">-</span><span class="element">&gt;resource_id</span><span class="plain">);</span>
<span class="functiontext">Writer::four_word</span><span class="plain">(</span><span class="identifier">IFF</span><span class="plain">, </span><span class="identifier">first_byte_after_index</span><span class="plain"> + </span><span class="identifier">chunk</span><span class="plain">-</span><span class="element">&gt;byte_offset</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP24">&#167;24</a>.</p>
<p class="inwebparagraph"><a id="SP24_3"></a><b>&#167;24.3. </b>Most of the chunks we put in exist on disc without their headers, but AIFF
sound files are an exception, because those are IFF files in their own right;
so they come with ready-made headers.
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Write the chunk</span> <span class="cwebmacronumber">24.3</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">bytes_to_copy</span><span class="plain">;</span>
<span class="reserved">char</span><span class="plain"> *</span><span class="identifier">type</span><span class="plain"> = </span><span class="identifier">chunk</span><span class="plain">-</span><span class="element">&gt;chunk_type</span><span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="functiontext">Writer::chunk_type_is_already_an_IFF</span><span class="plain">(</span><span class="identifier">type</span><span class="plain">) == </span><span class="constant">FALSE</span><span class="plain">) {</span>
<span class="identifier">fprintf</span><span class="plain">(</span><span class="identifier">IFF</span><span class="plain">, </span><span class="string">"%s"</span><span class="plain">, </span><span class="identifier">type</span><span class="plain">);</span>
<span class="functiontext">Writer::four_word</span><span class="plain">(</span><span class="identifier">IFF</span><span class="plain">, </span><span class="identifier">chunk</span><span class="plain">-</span><span class="element">&gt;size</span><span class="plain"> - 8); </span> <span class="comment">offset to end of chunk after the 8 bytes so far</span>
<span class="identifier">bytes_to_copy</span><span class="plain"> = </span><span class="identifier">chunk</span><span class="plain">-</span><span class="element">&gt;size</span><span class="plain"> - 8; </span> <span class="comment">since here the chunk size included 8 extra</span>
<span class="plain">} </span><span class="reserved">else</span><span class="plain"> {</span>
<span class="identifier">bytes_to_copy</span><span class="plain"> = </span><span class="identifier">chunk</span><span class="plain">-</span><span class="element">&gt;size</span><span class="plain">; </span> <span class="comment">whereas here the chunk size was genuinely the file size</span>
<span class="plain">}</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">chunk</span><span class="plain">-</span><span class="element">&gt;length_of_data_in_memory</span><span class="plain"> &gt;= 0)</span>
&lt;<span class="cwebmacro">Copy that many bytes from memory</span> <span class="cwebmacronumber">24.3.2</span>&gt;
<span class="reserved">else</span>
&lt;<span class="cwebmacro">Copy that many bytes from the chunk file on the disc</span> <span class="cwebmacronumber">24.3.1</span>&gt;<span class="plain">;</span>
<span class="reserved">if</span><span class="plain"> ((</span><span class="identifier">bytes_to_copy</span><span class="plain"> % 2) == 1) </span><span class="functiontext">Writer::one_byte</span><span class="plain">(</span><span class="identifier">IFF</span><span class="plain">, 0); </span> <span class="comment">as we allowed for above</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP24">&#167;24</a>.</p>
<p class="inwebparagraph"><a id="SP24_3_1"></a><b>&#167;24.3.1. </b>Sometimes the chunk's contents are on disc:
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Copy that many bytes from the chunk file on the disc</span> <span class="cwebmacronumber">24.3.1</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">FILE</span><span class="plain"> *</span><span class="identifier">CHUNKSUB</span><span class="plain"> = </span><span class="functiontext">BinaryFiles::open_for_reading</span><span class="plain">(</span><span class="identifier">chunk</span><span class="plain">-</span><span class="element">&gt;chunk_file</span><span class="plain">);</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="identifier">bytes_to_copy</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">j</span><span class="plain"> = </span><span class="identifier">fgetc</span><span class="plain">(</span><span class="identifier">CHUNKSUB</span><span class="plain">);</span>
<span class="reserved">if</span><span class="plain"> (</span><span class="identifier">j</span><span class="plain"> == </span><span class="identifier">EOF</span><span class="plain">) </span><span class="functiontext">BlorbErrors::fatal_fs</span><span class="plain">(</span><span class="string">"chunk ran out incomplete"</span><span class="plain">, </span><span class="identifier">chunk</span><span class="plain">-</span><span class="element">&gt;chunk_file</span><span class="plain">);</span>
<span class="functiontext">Writer::one_byte</span><span class="plain">(</span><span class="identifier">IFF</span><span class="plain">, </span><span class="identifier">j</span><span class="plain">);</span>
<span class="plain">}</span>
<span class="functiontext">BinaryFiles::close</span><span class="plain">(</span><span class="identifier">CHUNKSUB</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP24_3">&#167;24.3</a>.</p>
<p class="inwebparagraph"><a id="SP24_3_2"></a><b>&#167;24.3.2. </b>And sometimes, for shorter things, they are in memory:
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Copy that many bytes from memory</span> <span class="cwebmacronumber">24.3.2</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">i</span><span class="plain">;</span>
<span class="reserved">for</span><span class="plain"> (</span><span class="identifier">i</span><span class="plain">=0; </span><span class="identifier">i</span><span class="plain">&lt;</span><span class="identifier">bytes_to_copy</span><span class="plain">; </span><span class="identifier">i</span><span class="plain">++) {</span>
<span class="reserved">int</span><span class="plain"> </span><span class="identifier">j</span><span class="plain"> = (</span><span class="reserved">int</span><span class="plain">) (</span><span class="identifier">chunk</span><span class="plain">-</span><span class="element">&gt;data_in_memory</span><span class="plain">[</span><span class="identifier">i</span><span class="plain">]);</span>
<span class="functiontext">Writer::one_byte</span><span class="plain">(</span><span class="identifier">IFF</span><span class="plain">, </span><span class="identifier">j</span><span class="plain">);</span>
<span class="plain">}</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP24_3">&#167;24.3</a>.</p>
<p class="inwebparagraph"><a id="SP24_4"></a><b>&#167;24.4. </b>For debugging purposes only:
</p>
<p class="macrodefinition"><code class="display">
&lt;<span class="cwebmacrodefn">Print out a copy of the chunk table</span> <span class="cwebmacronumber">24.4</span>&gt; =
</code></p>
<pre class="displaydefn">
<span class="identifier">PRINT</span><span class="plain">(</span><span class="string">"! Chunk table:\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
<span class="reserved">chunk_metadata</span><span class="plain"> *</span><span class="identifier">chunk</span><span class="plain">;</span>
<span class="identifier">LOOP_OVER</span><span class="plain">(</span><span class="identifier">chunk</span><span class="plain">, </span><span class="reserved">chunk_metadata</span><span class="plain">)</span>
<span class="identifier">PRINT</span><span class="plain">(</span><span class="string">"! Chunk %s %06x %s %d &lt;%f&gt;\</span><span class="plain">n</span><span class="string">"</span><span class="plain">,</span>
<span class="identifier">chunk</span><span class="plain">-</span><span class="element">&gt;chunk_type</span><span class="plain">, </span><span class="identifier">chunk</span><span class="plain">-</span><span class="element">&gt;size</span><span class="plain">,</span>
<span class="plain">(</span><span class="identifier">chunk</span><span class="plain">-</span><span class="element">&gt;index_entry</span><span class="plain">)?(</span><span class="identifier">chunk</span><span class="plain">-</span><span class="element">&gt;index_entry</span><span class="plain">):</span><span class="string">"unindexed"</span><span class="plain">,</span>
<span class="identifier">chunk</span><span class="plain">-</span><span class="element">&gt;resource_id</span><span class="plain">,</span>
<span class="identifier">chunk</span><span class="plain">-</span><span class="element">&gt;chunk_file</span><span class="plain">);</span>
<span class="identifier">PRINT</span><span class="plain">(</span><span class="string">"! End of chunk table\</span><span class="plain">n</span><span class="string">"</span><span class="plain">);</span>
</pre>
<p class="inwebparagraph"></p>
<p class="endnote">This code is used in <a href="#SP24">&#167;24</a>.</p>
<hr class="tocbar">
<ul class="toc"><li><i>(This section begins Chapter 2: Blorbs.)</i></li><li><i>(This section ends Chapter 2: Blorbs.)</i></li></ul><hr class="tocbar">
<!--End of weave-->
</main>
</body>
</html>