mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 18:18:18 +00:00
384 lines
12 KiB
Perl
384 lines
12 KiB
Perl
|
###############################################################################
|
||
|
#
|
||
|
# Package: NaturalDocs::ImageReferenceTable
|
||
|
#
|
||
|
###############################################################################
|
||
|
#
|
||
|
# A <NaturalDocs::SourceDB>-based package that manages all the image references appearing in source files.
|
||
|
#
|
||
|
###############################################################################
|
||
|
|
||
|
# This file is part of Natural Docs, which is Copyright (C) 2003-2008 Greg Valure
|
||
|
# Natural Docs is licensed under the GPL
|
||
|
|
||
|
use strict;
|
||
|
use integer;
|
||
|
|
||
|
use NaturalDocs::ImageReferenceTable::String;
|
||
|
use NaturalDocs::ImageReferenceTable::Reference;
|
||
|
|
||
|
|
||
|
package NaturalDocs::ImageReferenceTable;
|
||
|
|
||
|
use base 'NaturalDocs::SourceDB::Extension';
|
||
|
|
||
|
|
||
|
###############################################################################
|
||
|
# Group: Information
|
||
|
|
||
|
#
|
||
|
# Topic: Usage
|
||
|
#
|
||
|
# - <NaturalDocs::Project> and <NaturalDocs::SourceDB> must be initialized before this package can be used.
|
||
|
#
|
||
|
# - Call <Register()> before using.
|
||
|
#
|
||
|
#
|
||
|
# Topic: Programming Notes
|
||
|
#
|
||
|
# When working on this code, remember that there are three things it has to juggle.
|
||
|
#
|
||
|
# - The information in <NaturalDocs::SourceDB>.
|
||
|
# - Image file references in <NaturalDocs::Project>.
|
||
|
# - Source file rebuilding on changes.
|
||
|
#
|
||
|
# Managing the actual image files will be handled between <NaturalDocs::Project> and the <NaturalDocs::Builder>
|
||
|
# sub-packages.
|
||
|
#
|
||
|
#
|
||
|
# Topic: Implementation
|
||
|
#
|
||
|
# Managing image references is simpler than managing the references in <NaturalDocs::SymbolTable>. In SymbolTable,
|
||
|
# you have to worry about reference targets popping into and out of existence. A link may go to a file that hasn't been
|
||
|
# reparsed yet and the target may no longer exist. We have to deal with that when we know it, which may be after the
|
||
|
# reference's file was parsed. Also, a new definition may appear that serves as a better interpretation of a link than its
|
||
|
# current target, and again we may only know that after the reference's file has been parsed already. So we have to deal
|
||
|
# with scores and potential symbols and each symbol knowing exactly what links to it and so forth.
|
||
|
#
|
||
|
# Not so with image references. All possible targets (all possible image files) are known by <NaturalDocs::Project> early
|
||
|
# on and will remain consistent throughout execution. So because of that, we can get away with only storing reference
|
||
|
# counts with each image and determining exactly where a reference points to as we find them.
|
||
|
#
|
||
|
# Reference counts are stored with the image file information in <NaturalDocs::Project>. However, it is not loaded and
|
||
|
# saved to disk by it. Rather, it is regenerated by this package when it loads <ImageReferenceTable.nd>.
|
||
|
# NaturalDocs::Project only stores the last modification time (so it can add files to the build list if they've changed) and
|
||
|
# whether it had any references at all on the last run (so it knows whether it should care if they've changed.)
|
||
|
# ImageReferenceTable.nd stores each reference's target, width, and height. Whether their interpretations have changed is
|
||
|
# dealt with in the <Load()> function, again since the list of targets (image files) is constant.
|
||
|
#
|
||
|
# The package is based on <NaturalDocs::SourceDB>, so read it's documentation for more information on how it works.
|
||
|
#
|
||
|
|
||
|
|
||
|
###############################################################################
|
||
|
# Group: Variables
|
||
|
|
||
|
|
||
|
#
|
||
|
# var: extensionID
|
||
|
# The <ExtensionID> granted by <NaturalDocs::SourceDB>.
|
||
|
#
|
||
|
my $extensionID;
|
||
|
|
||
|
|
||
|
|
||
|
###############################################################################
|
||
|
# Group: Files
|
||
|
|
||
|
|
||
|
#
|
||
|
# File: ImageReferenceTable.nd
|
||
|
#
|
||
|
# The data file which stores all the image references from the last run of Natural Docs.
|
||
|
#
|
||
|
# Format:
|
||
|
#
|
||
|
# > [Standard Binary Header]
|
||
|
#
|
||
|
# It starts with the standard binary header from <NaturalDocs::BinaryFile>.
|
||
|
#
|
||
|
# > [Image Reference String or undef]
|
||
|
# > [AString16: target file]
|
||
|
# > [UInt16: target width or 0]
|
||
|
# > [UInt16: target height or 0]
|
||
|
#
|
||
|
# For each <ImageReferenceString>, it's target, width, and height are stored. The target is needed so we can tell if it
|
||
|
# changed from the last run, and the dimensions are needed because if the target hasn't changed but the file's dimensions
|
||
|
# have, the source files need to be rebuilt.
|
||
|
#
|
||
|
# <ImageReferenceStrings> are encoded by <NaturalDocs::ImageReferenceTable::String>.
|
||
|
#
|
||
|
# > [AString16: definition file or undef] ...
|
||
|
#
|
||
|
# Then comes a series of AString16s for all the files that define the reference until it hits an undef.
|
||
|
#
|
||
|
# This whole series is repeated for each <ImageReferenceString> until it hits an undef.
|
||
|
#
|
||
|
# Revisions:
|
||
|
#
|
||
|
# 1.4:
|
||
|
#
|
||
|
# - The file was added to Natural Docs.
|
||
|
#
|
||
|
|
||
|
|
||
|
|
||
|
###############################################################################
|
||
|
# Group: Functions
|
||
|
|
||
|
|
||
|
#
|
||
|
# Function: Register
|
||
|
# Registers the package with <NaturalDocs::SourceDB>.
|
||
|
#
|
||
|
sub Register
|
||
|
{
|
||
|
my $self = shift;
|
||
|
$extensionID = NaturalDocs::SourceDB->RegisterExtension($self, 0);
|
||
|
};
|
||
|
|
||
|
|
||
|
#
|
||
|
# Function: Load
|
||
|
#
|
||
|
# Loads the data from <ImageReferenceTable.nd>. Returns whether it was successful.
|
||
|
#
|
||
|
sub Load # => bool
|
||
|
{
|
||
|
my $self = shift;
|
||
|
|
||
|
if (NaturalDocs::Settings->RebuildData())
|
||
|
{ return 0; };
|
||
|
|
||
|
# The file format hasn't changed since it was introduced.
|
||
|
if (!NaturalDocs::BinaryFile->OpenForReading( NaturalDocs::Project->DataFile('ImageReferenceTable.nd') ))
|
||
|
{ return 0; };
|
||
|
|
||
|
|
||
|
# [Image Reference String or undef]
|
||
|
while (my $referenceString = NaturalDocs::ImageReferenceTable::String->FromBinaryFile())
|
||
|
{
|
||
|
NaturalDocs::SourceDB->AddItem($extensionID, $referenceString,
|
||
|
NaturalDocs::ImageReferenceTable::Reference->New());
|
||
|
|
||
|
# [AString16: target file]
|
||
|
# [UInt16: target width or 0]
|
||
|
# [UInt16: target height or 0]
|
||
|
|
||
|
my $targetFile = NaturalDocs::BinaryFile->GetAString16();
|
||
|
my $width = NaturalDocs::BinaryFile->GetUInt16();
|
||
|
my $height = NaturalDocs::BinaryFile->GetUInt16();
|
||
|
|
||
|
my $newTargetFile = $self->SetReferenceTarget($referenceString);
|
||
|
my $newWidth;
|
||
|
my $newHeight;
|
||
|
|
||
|
if ($newTargetFile)
|
||
|
{
|
||
|
NaturalDocs::Project->AddImageFileReference($newTargetFile);
|
||
|
($newWidth, $newHeight) = NaturalDocs::Project->ImageFileDimensions($newTargetFile);
|
||
|
};
|
||
|
|
||
|
my $rebuildDefinitions = ($newTargetFile ne $targetFile || $newWidth != $width || $newHeight != $height);
|
||
|
|
||
|
|
||
|
# [AString16: definition file or undef] ...
|
||
|
while (my $definitionFile = NaturalDocs::BinaryFile->GetAString16())
|
||
|
{
|
||
|
NaturalDocs::SourceDB->AddDefinition($extensionID, $referenceString, $definitionFile);
|
||
|
|
||
|
if ($rebuildDefinitions)
|
||
|
{ NaturalDocs::Project->RebuildFile($definitionFile); };
|
||
|
};
|
||
|
};
|
||
|
|
||
|
|
||
|
NaturalDocs::BinaryFile->Close();
|
||
|
return 1;
|
||
|
};
|
||
|
|
||
|
|
||
|
#
|
||
|
# Function: Save
|
||
|
#
|
||
|
# Saves the data to <ImageReferenceTable.nd>.
|
||
|
#
|
||
|
sub Save
|
||
|
{
|
||
|
my $self = shift;
|
||
|
|
||
|
my $references = NaturalDocs::SourceDB->GetAllItemsHashRef($extensionID);
|
||
|
|
||
|
NaturalDocs::BinaryFile->OpenForWriting( NaturalDocs::Project->DataFile('ImageReferenceTable.nd') );
|
||
|
|
||
|
while (my ($referenceString, $referenceObject) = each %$references)
|
||
|
{
|
||
|
# [Image Reference String or undef]
|
||
|
# [AString16: target file]
|
||
|
# [UInt16: target width or 0]
|
||
|
# [UInt16: target height or 0]
|
||
|
|
||
|
NaturalDocs::ImageReferenceTable::String->ToBinaryFile($referenceString);
|
||
|
|
||
|
my $target = $referenceObject->Target();
|
||
|
my ($width, $height);
|
||
|
|
||
|
if ($target)
|
||
|
{ ($width, $height) = NaturalDocs::Project->ImageFileDimensions($target); };
|
||
|
|
||
|
NaturalDocs::BinaryFile->WriteAString16( $referenceObject->Target() );
|
||
|
NaturalDocs::BinaryFile->WriteUInt16( ($width || 0) );
|
||
|
NaturalDocs::BinaryFile->WriteUInt16( ($height || 0) );
|
||
|
|
||
|
# [AString16: definition file or undef] ...
|
||
|
|
||
|
my $definitions = $referenceObject->GetAllDefinitionsHashRef();
|
||
|
|
||
|
foreach my $definition (keys %$definitions)
|
||
|
{ NaturalDocs::BinaryFile->WriteAString16($definition); };
|
||
|
|
||
|
NaturalDocs::BinaryFile->WriteAString16(undef);
|
||
|
};
|
||
|
|
||
|
NaturalDocs::ImageReferenceTable::String->ToBinaryFile(undef);
|
||
|
|
||
|
NaturalDocs::BinaryFile->Close();
|
||
|
};
|
||
|
|
||
|
|
||
|
#
|
||
|
# Function: AddReference
|
||
|
#
|
||
|
# Adds a new image reference.
|
||
|
#
|
||
|
sub AddReference #(FileName file, string referenceText)
|
||
|
{
|
||
|
my ($self, $file, $referenceText) = @_;
|
||
|
|
||
|
my $referenceString = NaturalDocs::ImageReferenceTable::String->Make($file, $referenceText);
|
||
|
|
||
|
if (!NaturalDocs::SourceDB->HasItem($extensionID, $referenceString))
|
||
|
{
|
||
|
my $referenceObject = NaturalDocs::ImageReferenceTable::Reference->New();
|
||
|
NaturalDocs::SourceDB->AddItem($extensionID, $referenceString, $referenceObject);
|
||
|
|
||
|
my $target = $self->SetReferenceTarget($referenceString);
|
||
|
if ($target)
|
||
|
{ NaturalDocs::Project->AddImageFileReference($target); };
|
||
|
};
|
||
|
|
||
|
NaturalDocs::SourceDB->AddDefinition($extensionID, $referenceString, $file);
|
||
|
};
|
||
|
|
||
|
|
||
|
#
|
||
|
# Function: OnDeletedDefinition
|
||
|
#
|
||
|
# Called for each definition deleted by <NaturalDocs::SourceDB>. This is called *after* the definition has been deleted from
|
||
|
# the database, so don't expect to be able to read it.
|
||
|
#
|
||
|
sub OnDeletedDefinition #(ImageReferenceString referenceString, FileName file, bool wasLastDefinition)
|
||
|
{
|
||
|
my ($self, $referenceString, $file, $wasLastDefinition) = @_;
|
||
|
|
||
|
if ($wasLastDefinition)
|
||
|
{
|
||
|
my $referenceObject = NaturalDocs::SourceDB->GetItem($extensionID, $referenceString);
|
||
|
my $target = $referenceObject->Target();
|
||
|
|
||
|
if ($target)
|
||
|
{ NaturalDocs::Project->DeleteImageFileReference($target); };
|
||
|
|
||
|
NaturalDocs::SourceDB->DeleteItem($extensionID, $referenceString);
|
||
|
};
|
||
|
};
|
||
|
|
||
|
|
||
|
#
|
||
|
# Function: GetReferenceTarget
|
||
|
#
|
||
|
# Returns the image file the reference resolves to, or undef if none.
|
||
|
#
|
||
|
# Parameters:
|
||
|
#
|
||
|
# sourceFile - The source <FileName> the reference appears in.
|
||
|
# text - The reference text.
|
||
|
#
|
||
|
sub GetReferenceTarget #(FileName sourceFile, string text) => FileName
|
||
|
{
|
||
|
my ($self, $sourceFile, $text) = @_;
|
||
|
|
||
|
my $referenceString = NaturalDocs::ImageReferenceTable::String->Make($sourceFile, $text);
|
||
|
my $reference = NaturalDocs::SourceDB->GetItem($extensionID, $referenceString);
|
||
|
|
||
|
if (!defined $reference)
|
||
|
{ return undef; }
|
||
|
else
|
||
|
{ return $reference->Target(); };
|
||
|
};
|
||
|
|
||
|
|
||
|
#
|
||
|
# Function: SetReferenceTarget
|
||
|
#
|
||
|
# Determines the best target for the passed <ImageReferenceString> and sets it on the
|
||
|
# <NaturalDocs::ImageReferenceTable::Reference> object. Returns the new target <FileName>. Does *not* add any source
|
||
|
# files to the bulid list.
|
||
|
#
|
||
|
sub SetReferenceTarget #(ImageReferenceString referenceString) => FileName
|
||
|
{
|
||
|
my ($self, $referenceString) = @_;
|
||
|
|
||
|
my $referenceObject = NaturalDocs::SourceDB->GetItem($extensionID, $referenceString);
|
||
|
my ($sourcePath, $text) = NaturalDocs::ImageReferenceTable::String->InformationOf($referenceString);
|
||
|
|
||
|
|
||
|
# Try the path relative to the source file first.
|
||
|
|
||
|
my $target;
|
||
|
|
||
|
my $imageFile = NaturalDocs::File->JoinPaths($sourcePath, $text);
|
||
|
my $exists = NaturalDocs::Project->ImageFileExists($imageFile);
|
||
|
|
||
|
|
||
|
# Then try relative image directories.
|
||
|
|
||
|
if (!$exists)
|
||
|
{
|
||
|
my $relativeImageDirectories = NaturalDocs::Settings->RelativeImageDirectories();
|
||
|
|
||
|
for (my $i = 0; $i < scalar @$relativeImageDirectories && !$exists; $i++)
|
||
|
{
|
||
|
$imageFile = NaturalDocs::File->JoinPaths($sourcePath, $relativeImageDirectories->[$i], 1);
|
||
|
$imageFile = NaturalDocs::File->JoinPaths($imageFile, $text);
|
||
|
|
||
|
$exists = NaturalDocs::Project->ImageFileExists($imageFile);
|
||
|
};
|
||
|
};
|
||
|
|
||
|
|
||
|
# Then try absolute image directories.
|
||
|
|
||
|
if (!$exists)
|
||
|
{
|
||
|
my $imageDirectories = NaturalDocs::Settings->ImageDirectories();
|
||
|
|
||
|
for (my $i = 0; $i < scalar @$imageDirectories && !$exists; $i++)
|
||
|
{
|
||
|
$imageFile = NaturalDocs::File->JoinPaths($imageDirectories->[$i], $text);
|
||
|
$exists = NaturalDocs::Project->ImageFileExists($imageFile);
|
||
|
};
|
||
|
};
|
||
|
|
||
|
|
||
|
if ($exists)
|
||
|
{ $target = NaturalDocs::Project->ImageFileCapitalization($imageFile); };
|
||
|
#else leave it as undef.
|
||
|
|
||
|
$referenceObject->SetTarget($target);
|
||
|
return $target;
|
||
|
};
|
||
|
|
||
|
|
||
|
1;
|