1
###############################################################################
3
# Package: NaturalDocs::ImageReferenceTable
5
###############################################################################
7
# A <NaturalDocs::SourceDB>-based package that manages all the image references appearing in source files.
9
###############################################################################
11
# This file is part of Natural Docs, which is Copyright (C) 2003-2008 Greg Valure
12
# Natural Docs is licensed under the GPL
17
use NaturalDocs::ImageReferenceTable::String;
18
use NaturalDocs::ImageReferenceTable::Reference;
21
package NaturalDocs::ImageReferenceTable;
23
use base 'NaturalDocs::SourceDB::Extension';
26
###############################################################################
32
# - <NaturalDocs::Project> and <NaturalDocs::SourceDB> must be initialized before this package can be used.
34
# - Call <Register()> before using.
37
# Topic: Programming Notes
39
# When working on this code, remember that there are three things it has to juggle.
41
# - The information in <NaturalDocs::SourceDB>.
42
# - Image file references in <NaturalDocs::Project>.
43
# - Source file rebuilding on changes.
45
# Managing the actual image files will be handled between <NaturalDocs::Project> and the <NaturalDocs::Builder>
49
# Topic: Implementation
51
# Managing image references is simpler than managing the references in <NaturalDocs::SymbolTable>. In SymbolTable,
52
# you have to worry about reference targets popping into and out of existence. A link may go to a file that hasn't been
53
# reparsed yet and the target may no longer exist. We have to deal with that when we know it, which may be after the
54
# reference's file was parsed. Also, a new definition may appear that serves as a better interpretation of a link than its
55
# current target, and again we may only know that after the reference's file has been parsed already. So we have to deal
56
# with scores and potential symbols and each symbol knowing exactly what links to it and so forth.
58
# Not so with image references. All possible targets (all possible image files) are known by <NaturalDocs::Project> early
59
# on and will remain consistent throughout execution. So because of that, we can get away with only storing reference
60
# counts with each image and determining exactly where a reference points to as we find them.
62
# Reference counts are stored with the image file information in <NaturalDocs::Project>. However, it is not loaded and
63
# saved to disk by it. Rather, it is regenerated by this package when it loads <ImageReferenceTable.nd>.
64
# NaturalDocs::Project only stores the last modification time (so it can add files to the build list if they've changed) and
65
# whether it had any references at all on the last run (so it knows whether it should care if they've changed.)
66
# ImageReferenceTable.nd stores each reference's target, width, and height. Whether their interpretations have changed is
67
# dealt with in the <Load()> function, again since the list of targets (image files) is constant.
69
# The package is based on <NaturalDocs::SourceDB>, so read it's documentation for more information on how it works.
73
###############################################################################
79
# The <ExtensionID> granted by <NaturalDocs::SourceDB>.
85
###############################################################################
90
# File: ImageReferenceTable.nd
92
# The data file which stores all the image references from the last run of Natural Docs.
96
# > [Standard Binary Header]
98
# It starts with the standard binary header from <NaturalDocs::BinaryFile>.
100
# > [Image Reference String or undef]
101
# > [AString16: target file]
102
# > [UInt16: target width or 0]
103
# > [UInt16: target height or 0]
105
# For each <ImageReferenceString>, it's target, width, and height are stored. The target is needed so we can tell if it
106
# changed from the last run, and the dimensions are needed because if the target hasn't changed but the file's dimensions
107
# have, the source files need to be rebuilt.
109
# <ImageReferenceStrings> are encoded by <NaturalDocs::ImageReferenceTable::String>.
111
# > [AString16: definition file or undef] ...
113
# Then comes a series of AString16s for all the files that define the reference until it hits an undef.
115
# This whole series is repeated for each <ImageReferenceString> until it hits an undef.
121
# - The file was added to Natural Docs.
126
###############################################################################
132
# Registers the package with <NaturalDocs::SourceDB>.
137
$extensionID = NaturalDocs::SourceDB->RegisterExtension($self, 0);
144
# Loads the data from <ImageReferenceTable.nd>. Returns whether it was successful.
150
if (NaturalDocs::Settings->RebuildData())
153
# The file format hasn't changed since it was introduced.
154
if (!NaturalDocs::BinaryFile->OpenForReading( NaturalDocs::Project->DataFile('ImageReferenceTable.nd') ))
158
# [Image Reference String or undef]
159
while (my $referenceString = NaturalDocs::ImageReferenceTable::String->FromBinaryFile())
161
NaturalDocs::SourceDB->AddItem($extensionID, $referenceString,
162
NaturalDocs::ImageReferenceTable::Reference->New());
164
# [AString16: target file]
165
# [UInt16: target width or 0]
166
# [UInt16: target height or 0]
168
my $targetFile = NaturalDocs::BinaryFile->GetAString16();
169
my $width = NaturalDocs::BinaryFile->GetUInt16();
170
my $height = NaturalDocs::BinaryFile->GetUInt16();
172
my $newTargetFile = $self->SetReferenceTarget($referenceString);
178
NaturalDocs::Project->AddImageFileReference($newTargetFile);
179
($newWidth, $newHeight) = NaturalDocs::Project->ImageFileDimensions($newTargetFile);
182
my $rebuildDefinitions = ($newTargetFile ne $targetFile || $newWidth != $width || $newHeight != $height);
185
# [AString16: definition file or undef] ...
186
while (my $definitionFile = NaturalDocs::BinaryFile->GetAString16())
188
NaturalDocs::SourceDB->AddDefinition($extensionID, $referenceString, $definitionFile);
190
if ($rebuildDefinitions)
191
{ NaturalDocs::Project->RebuildFile($definitionFile); };
196
NaturalDocs::BinaryFile->Close();
204
# Saves the data to <ImageReferenceTable.nd>.
210
my $references = NaturalDocs::SourceDB->GetAllItemsHashRef($extensionID);
212
NaturalDocs::BinaryFile->OpenForWriting( NaturalDocs::Project->DataFile('ImageReferenceTable.nd') );
214
while (my ($referenceString, $referenceObject) = each %$references)
216
# [Image Reference String or undef]
217
# [AString16: target file]
218
# [UInt16: target width or 0]
219
# [UInt16: target height or 0]
221
NaturalDocs::ImageReferenceTable::String->ToBinaryFile($referenceString);
223
my $target = $referenceObject->Target();
224
my ($width, $height);
227
{ ($width, $height) = NaturalDocs::Project->ImageFileDimensions($target); };
229
NaturalDocs::BinaryFile->WriteAString16( $referenceObject->Target() );
230
NaturalDocs::BinaryFile->WriteUInt16( ($width || 0) );
231
NaturalDocs::BinaryFile->WriteUInt16( ($height || 0) );
233
# [AString16: definition file or undef] ...
235
my $definitions = $referenceObject->GetAllDefinitionsHashRef();
237
foreach my $definition (keys %$definitions)
238
{ NaturalDocs::BinaryFile->WriteAString16($definition); };
240
NaturalDocs::BinaryFile->WriteAString16(undef);
243
NaturalDocs::ImageReferenceTable::String->ToBinaryFile(undef);
245
NaturalDocs::BinaryFile->Close();
250
# Function: AddReference
252
# Adds a new image reference.
254
sub AddReference #(FileName file, string referenceText)
256
my ($self, $file, $referenceText) = @_;
258
my $referenceString = NaturalDocs::ImageReferenceTable::String->Make($file, $referenceText);
260
if (!NaturalDocs::SourceDB->HasItem($extensionID, $referenceString))
262
my $referenceObject = NaturalDocs::ImageReferenceTable::Reference->New();
263
NaturalDocs::SourceDB->AddItem($extensionID, $referenceString, $referenceObject);
265
my $target = $self->SetReferenceTarget($referenceString);
267
{ NaturalDocs::Project->AddImageFileReference($target); };
270
NaturalDocs::SourceDB->AddDefinition($extensionID, $referenceString, $file);
275
# Function: OnDeletedDefinition
277
# Called for each definition deleted by <NaturalDocs::SourceDB>. This is called *after* the definition has been deleted from
278
# the database, so don't expect to be able to read it.
280
sub OnDeletedDefinition #(ImageReferenceString referenceString, FileName file, bool wasLastDefinition)
282
my ($self, $referenceString, $file, $wasLastDefinition) = @_;
284
if ($wasLastDefinition)
286
my $referenceObject = NaturalDocs::SourceDB->GetItem($extensionID, $referenceString);
287
my $target = $referenceObject->Target();
290
{ NaturalDocs::Project->DeleteImageFileReference($target); };
292
NaturalDocs::SourceDB->DeleteItem($extensionID, $referenceString);
298
# Function: GetReferenceTarget
300
# Returns the image file the reference resolves to, or undef if none.
304
# sourceFile - The source <FileName> the reference appears in.
305
# text - The reference text.
307
sub GetReferenceTarget #(FileName sourceFile, string text) => FileName
309
my ($self, $sourceFile, $text) = @_;
311
my $referenceString = NaturalDocs::ImageReferenceTable::String->Make($sourceFile, $text);
312
my $reference = NaturalDocs::SourceDB->GetItem($extensionID, $referenceString);
314
if (!defined $reference)
317
{ return $reference->Target(); };
322
# Function: SetReferenceTarget
324
# Determines the best target for the passed <ImageReferenceString> and sets it on the
325
# <NaturalDocs::ImageReferenceTable::Reference> object. Returns the new target <FileName>. Does *not* add any source
326
# files to the bulid list.
328
sub SetReferenceTarget #(ImageReferenceString referenceString) => FileName
330
my ($self, $referenceString) = @_;
332
my $referenceObject = NaturalDocs::SourceDB->GetItem($extensionID, $referenceString);
333
my ($sourcePath, $text) = NaturalDocs::ImageReferenceTable::String->InformationOf($referenceString);
336
# Try the path relative to the source file first.
340
my $imageFile = NaturalDocs::File->JoinPaths($sourcePath, $text);
341
my $exists = NaturalDocs::Project->ImageFileExists($imageFile);
344
# Then try relative image directories.
348
my $relativeImageDirectories = NaturalDocs::Settings->RelativeImageDirectories();
350
for (my $i = 0; $i < scalar @$relativeImageDirectories && !$exists; $i++)
352
$imageFile = NaturalDocs::File->JoinPaths($sourcePath, $relativeImageDirectories->[$i], 1);
353
$imageFile = NaturalDocs::File->JoinPaths($imageFile, $text);
355
$exists = NaturalDocs::Project->ImageFileExists($imageFile);
360
# Then try absolute image directories.
364
my $imageDirectories = NaturalDocs::Settings->ImageDirectories();
366
for (my $i = 0; $i < scalar @$imageDirectories && !$exists; $i++)
368
$imageFile = NaturalDocs::File->JoinPaths($imageDirectories->[$i], $text);
369
$exists = NaturalDocs::Project->ImageFileExists($imageFile);
375
{ $target = NaturalDocs::Project->ImageFileCapitalization($imageFile); };
376
#else leave it as undef.
378
$referenceObject->SetTarget($target);