Remove pandaapp completely

This commit is contained in:
rdb 2013-07-30 21:33:50 +00:00
parent 1735ae4600
commit 574199c94d
38 changed files with 0 additions and 8675 deletions

View File

@ -1,59 +0,0 @@
//
// Package.pp
//
// This file defines certain configuration variables that are to be
// written into the various make scripts. It is processed by ppremake
// (along with the Sources.pp files in each of the various
// directories) to generate build scripts appropriate to each
// environment.
//
// This is the package-specific file, which should be at the top of
// every source hierarchy. It generally gets the ball rolling, and is
// responsible for explicitly including all of the relevent Config.pp
// files.
// What is the name and version of this source tree?
#if $[eq $[PACKAGE],]
#define PACKAGE pandaapp
#define VERSION 0.80
#endif
// Where should we find the PANDATOOL source directory?
#if $[or $[CTPROJS],$[PANDATOOL]]
// If we are presently attached, use the environment variable.
#define PANDATOOL_SOURCE $[PANDATOOL]
#if $[eq $[PANDATOOL],]
#error You seem to be attached to some trees, but not PANDATOOL!
#endif
#else
// Otherwise, if we are not attached, we guess that the source is a
// sibling directory to this source root.
#define PANDATOOL_SOURCE $[standardize $[TOPDIR]/../pandatool]
#endif
// Where should we install PANDAAPP?
#if $[PANDAAPP_INSTALL]
#define PANDAAPP_INSTALL $[unixfilename $[PANDAAPP_INSTALL]]
#elif $[CTPROJS]
#define PANDAAPP_INSTALL $[PANDAAPP]/built
#if $[eq $[PANDAAPP],]
#error You seem to be attached to some trees, but not PANDAAPP!
#endif
#else
#defer PANDAAPP_INSTALL $[unixfilename $[INSTALL_DIR]]
#endif
// Also get the PANDATOOL Package file and everything that includes.
#if $[not $[isfile $[PANDATOOL_SOURCE]/Package.pp]]
#printvar PANDATOOL
#error PANDATOOL source directory not found from pandaapp! Are you attached properly?
#endif
#include $[PANDATOOL_SOURCE]/Package.pp
// Define the inter-tree dependencies.
#define NEEDS_TREES pandatool $[NEEDS_TREES]
#define DEPENDABLE_HEADER_DIRS $[DEPENDABLE_HEADER_DIRS] $[PANDATOOL_INSTALL]/include

View File

@ -1,4 +0,0 @@
// This is the toplevel directory. It contains configure.in and other
// stuff.
#define DIR_TYPE toplevel

View File

@ -1,4 +0,0 @@
// This is a group directory: a directory level above a number of
// source subdirectories.
#define DIR_TYPE group

View File

@ -1 +0,0 @@
#define INSTALL_CONFIG pandaapp.init

View File

@ -1 +0,0 @@
ATTACH pandatool

View File

@ -1,19 +0,0 @@
#define BUILD_DIRECTORY $[HAVE_OPENSSL]
#begin bin_target
#define TARGET httpbackup
#define LOCAL_LIBS pandaappbase
#define USE_PACKAGES ssl
#define OTHER_LIBS \
progbase pandatoolbase \
express:c downloader:c pandaexpress:m \
panda:m dtool:m dtoolconfig:m \
pystub
#define SOURCES \
backupCatalog.I backupCatalog.cxx backupCatalog.h \
httpBackup.cxx httpBackup.h
#end bin_target

View File

@ -1,59 +0,0 @@
// Filename: backupCatalog.I
// Created by: drose (29Jan03)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: BackupCatalog::Entry::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE BackupCatalog::Entry::
Entry() {
}
////////////////////////////////////////////////////////////////////
// Function: BackupCatalog::Entry::operator <
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool BackupCatalog::Entry::
operator < (const BackupCatalog::Entry &other) const {
return get_date() < other.get_date();
}
////////////////////////////////////////////////////////////////////
// Function: BackupCatalog::Entry::get_date
// Access: Public
// Description: Returns the date associated with the entry. This is
// the last-modified date provided by the server, if we
// have such a thing; or the downloaded date if that's
// all we have.
////////////////////////////////////////////////////////////////////
INLINE const HTTPDate &BackupCatalog::Entry::
get_date() const {
return _document_spec.has_date() ? _document_spec.get_date() : _download_date;
}
INLINE istream &
operator >> (istream &in, BackupCatalog::Entry &entry) {
entry.input(in);
return in;
}
INLINE ostream &
operator << (ostream &out, const BackupCatalog::Entry &entry) {
entry.output(out);
return out;
}

View File

@ -1,195 +0,0 @@
// Filename: backupCatalog.cxx
// Created by: drose (29Jan03)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "backupCatalog.h"
#include "indirectLess.h"
#include <algorithm>
// These are the characters that are not escaped when we write a
// filename out to the catalog. Really, the only reason we use
// URLSpec::quote() to protect the filenames is to escape spaces.
static const char * const acceptable_chars = "~/:";
////////////////////////////////////////////////////////////////////
// Function: BackupCatalog::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
BackupCatalog::
BackupCatalog() {
_dirty = false;
}
////////////////////////////////////////////////////////////////////
// Function: BackupCatalog::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
BackupCatalog::
~BackupCatalog() {
clear();
}
////////////////////////////////////////////////////////////////////
// Function: BackupCatalog::read
// Access: Public
// Description: Reads the catalog from the named file. Returns true
// on success, false on failure. On a false return, the
// catalog may have been partially read in.
////////////////////////////////////////////////////////////////////
bool BackupCatalog::
read(const Filename &filename) {
clear();
ifstream file;
if (!filename.open_read(file)) {
nout << "Unable to read: " << filename << "\n";
return false;
}
Entry *entry = new Entry;
file >> (*entry);
while (!file.fail() && !file.eof()) {
_table[entry->_document_name].push_back(entry);
_filenames.insert(entry->_filename);
entry = new Entry;
file >> (*entry);
}
// Delete the last Entry that we didn't use.
delete entry;
if (!file.eof()) {
// Oops, we had an error on one of the entries.
return false;
}
// Now sort all of the entries by date.
Table::iterator ti;
for (ti = _table.begin(); ti != _table.end(); ++ti) {
Entries &entries = (*ti).second;
sort(entries.begin(), entries.end(), IndirectLess<Entry>());
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: BackupCatalog::write
// Access: Public
// Description: Rewrites the catalog to the named file. Returns true
// on success, false on failure.
////////////////////////////////////////////////////////////////////
bool BackupCatalog::
write(const Filename &filename) {
ofstream file;
if (!filename.open_write(file)) {
nout << "Unable to write: " << filename << "\n";
return false;
}
Table::const_iterator ti;
for (ti = _table.begin(); ti != _table.end(); ++ti) {
const Entries &entries = (*ti).second;
Entries::const_iterator ei;
for (ei = entries.begin(); ei != entries.end(); ++ei) {
(*ei)->write(file);
file << "\n";
}
}
if (file) {
_dirty = false;
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: BackupCatalog::clear
// Access: Public
// Description: Completely empties the contents of the catalog.
////////////////////////////////////////////////////////////////////
void BackupCatalog::
clear() {
Table::iterator ti;
for (ti = _table.begin(); ti != _table.end(); ++ti) {
Entries &entries = (*ti).second;
Entries::iterator ei;
for (ei = entries.begin(); ei != entries.end(); ++ei) {
delete (*ei);
}
}
_dirty = false;
}
////////////////////////////////////////////////////////////////////
// Function: BackupCatalog::Entry::delete_file
// Access: Public
// Description: Deletes the file named by the entry, echoing the
// indicated reason to nout.
////////////////////////////////////////////////////////////////////
void BackupCatalog::Entry::
delete_file(const Filename &dirname, const string &reason) {
Filename pathname(dirname, _filename);
if (pathname.exists()) {
nout << "Deleting " << _filename << " (" << reason << ").\n";
if (!pathname.unlink()) {
nout << "unable to delete.\n";
}
} else {
nout << "Tried to delete " << _filename << " but it's already gone!\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: BackupCatalog::Entry::input
// Access: Public
// Description: Can be used to read in the catalog entry from a
// stream generated by either output() or write().
////////////////////////////////////////////////////////////////////
void BackupCatalog::Entry::
input(istream &in) {
in >> _document_name >> _filename >> _document_spec >> _download_date;
_document_name = URLSpec::unquote(_document_name);
_filename = URLSpec::unquote(_filename);
}
////////////////////////////////////////////////////////////////////
// Function: BackupCatalog::Entry::output
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void BackupCatalog::Entry::
output(ostream &out) const {
out << URLSpec::quote(_document_name, acceptable_chars) << " "
<< URLSpec::quote(_filename, acceptable_chars) << " "
<< _document_spec << " "
<< _download_date;
}
////////////////////////////////////////////////////////////////////
// Function: BackupCatalog::Entry::write
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void BackupCatalog::Entry::
write(ostream &out) const {
out << URLSpec::quote(_document_name, acceptable_chars) << " "
<< URLSpec::quote(_filename, acceptable_chars) << "\n";
_document_spec.write(out, 2);
out << " " << _download_date << "\n";
}

View File

@ -1,74 +0,0 @@
// Filename: backupCatalog.h
// Created by: drose (29Jan03)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef BACKUPCATALOG_H
#define BACKUPCATALOG_H
#include "pandaappbase.h"
#include "documentSpec.h"
#include "filename.h"
#include "pvector.h"
#include "pmap.h"
#include "pset.h"
////////////////////////////////////////////////////////////////////
// Class : BackupCatalog
// Description : This is the list of previous versions of this file
// (and possibly other files) stored in the "catalog", a
// text file within the download directory.
////////////////////////////////////////////////////////////////////
class BackupCatalog {
public:
BackupCatalog();
~BackupCatalog();
bool read(const Filename &filename);
bool write(const Filename &filename);
void clear();
class Entry {
public:
INLINE Entry();
INLINE bool operator < (const Entry &other) const;
INLINE const HTTPDate &get_date() const;
void delete_file(const Filename &dirname, const string &reason);
void input(istream &in);
void output(ostream &out) const;
void write(ostream &out) const;
string _document_name;
string _filename;
DocumentSpec _document_spec;
HTTPDate _download_date;
};
typedef pvector<Entry *> Entries;
typedef pmap<string, Entries> Table;
Table _table;
typedef pset<string> Filenames;
Filenames _filenames;
bool _dirty;
};
INLINE istream &operator >> (istream &in, BackupCatalog::Entry &entry);
INLINE ostream &operator << (ostream &out, const BackupCatalog::Entry &entry);
#include "backupCatalog.I"
#endif

View File

@ -1,519 +0,0 @@
// Filename: httpBackup.cxx
// Created by: drose (29Jan03)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "httpBackup.h"
#include "httpChannel.h"
static const int seconds_per_day = 60 * 60 * 24;
////////////////////////////////////////////////////////////////////
// Function: HTTPBackup::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
HTTPBackup::
HTTPBackup() {
clear_runlines();
add_runline("[opts] url");
add_runline("-check <days> url");
set_program_description
("This program is designed to run periodically as a "
"background task, e.g. via a cron job. It fetches the "
"latest copy of a document from an HTTP server and "
"stores it, along with an optional number of previous "
"versions, in a local directory so that it may be "
"backed up to tape.\n\n"
"If the copy on disk is already the same as the latest "
"copy available on the HTTP server, this program generally "
"does nothing (although it may delete old versions if they "
"have expired past the maximum age specified on the command "
"line).");
add_option
("p", "url", 0,
"Specifies the URL of the HTTP proxy server(s), if one is required. "
"Multiple servers may be specified by separating them with semicolons; "
"they will be tried in the order listed.",
&HTTPBackup::dispatch_string, &_got_proxy, &_proxy);
add_option
("a", "", 0,
"If this option is specified, the document is always downloaded every "
"time httpbackup runs, even if the document does not appear to have "
"been changed since last time.",
&HTTPBackup::dispatch_none, &_always_download, NULL);
add_option
("d", "dirname", 0,
"Specifies the name of the directory in which to store the backup "
"versions of the document. The default is '.', the current "
"directory.",
&HTTPBackup::dispatch_filename, NULL, &_dirname);
add_option
("c", "filename", 0,
"Specifies the name of the catalog file that httpbackup uses to "
"record the HTTP entity tags, etc., downloaded from previous "
"versions. If a relative filename is given, it is relative to "
"the directory specified by -d. The default is 'Catalog'.",
&HTTPBackup::dispatch_filename, NULL, &_catalog_name);
add_option
("n", "filename", 0,
"Specifies the name of the document that is being retrieved. This "
"name is written to the catalog file to identify entries for this "
"document, and is used to generate the filename to store the "
"backup versions. The default if this is omitted or empty is to use "
"the basename of the URL.",
&HTTPBackup::dispatch_string, NULL, &_document_name);
add_option
("s", "string", 0,
"Specifies how the date is appended onto the filename (see -n) for "
"each version of the file. This string should contain the sequence "
"of characters from strftime() that correspond to the desired date "
"format to append to the filename. The default is '.%Y-%m-%d.%H-%M', "
"or the year, month, day, hour, and minute. (The date is always "
"represented in GMT, according to HTTP convention.)",
&HTTPBackup::dispatch_string, NULL, &_version_append);
add_option
("maxage", "days", 0,
"Specifies the maximum age, in days, to keep an old version of the "
"file around. If unspecified, the default is no limit. This may "
"be a floating-point number.",
&HTTPBackup::dispatch_double, &_got_max_keep_days, &_max_keep_days);
add_option
("minage", "days", 0,
"Specifies the minimum age, in days, an old version of the file must "
"have before it is automatically deleted due to exceeding -maxver. "
"The default is 0. This may be a floating-point number.",
&HTTPBackup::dispatch_double, NULL, &_min_keep_days);
add_option
("maxver", "count", 0,
"Specifies the maximum number of old versions of the file to keep "
"around. If unspecified, the default is no limit.",
&HTTPBackup::dispatch_int, &_got_max_keep_versions, &_max_keep_versions);
add_option
("minver", "count", 0,
"Specifies the minimum number of old versions to keep after "
"deleting versions older than -maxage. The default is 1.",
&HTTPBackup::dispatch_int, NULL, &_min_keep_versions);
add_option
("check", "days", 0,
"Instead of downloading any document, check the date of the most recent "
"document downloaded. Returns success if that date is no more than the "
"indicated number of days old (which may be a floating-point number), "
"or failure otherwise.",
&HTTPBackup::dispatch_double, &_got_check_days, &_check_days);
_dirname = ".";
_catalog_name = "Catalog";
_version_append = ".%Y-%m-%d.%H-%M";
_max_keep_days = 0.0;
_min_keep_days = 0.0;
_max_keep_versions = 0;
_min_keep_versions = 1;
}
////////////////////////////////////////////////////////////////////
// Function: HTTPBackup::handle_args
// Access: Protected, Virtual
// Description: Does something with the additional arguments on the
// command line (after all the -options have been
// parsed). Returns true if the arguments are good,
// false otherwise.
////////////////////////////////////////////////////////////////////
bool HTTPBackup::
handle_args(ProgramBase::Args &args) {
if (_got_check_days && !_document_name.empty() && args.empty()) {
// If -check and -n are both specified, we don't really need to
// specify an URL. Accept it if we don't.
return true;
}
if (args.size() != 1) {
nout <<
"You must specify the URL of the document to download "
"on the command line.\n\n";
return false;
}
_url = URLSpec(args[0]);
if (!(_url.has_server() && _url.has_path())) {
nout
<< "Invalid URL specification: " << args[0] << "\n";
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: HTTPBackup::post_command_line
// Access: Protected, Virtual
// Description: This is called after the command line has been
// completely processed, and it gives the program a
// chance to do some last-minute processing and
// validation of the options and arguments. It should
// return true if everything is fine, false if there is
// an error.
////////////////////////////////////////////////////////////////////
bool HTTPBackup::
post_command_line() {
if (_got_proxy) {
_http.set_proxy_spec(_proxy);
}
if (!_catalog_name.is_fully_qualified()) {
_catalog_name = Filename(_dirname, _catalog_name);
}
if (_document_name.empty()) {
Filename pathname = _url.get_path();
_document_name = pathname.get_basename();
}
if (_min_keep_days < 0.0) {
nout << "Invalid -minage " << _min_keep_days << "\n";
return false;
}
if (_min_keep_versions < 0) {
nout << "Invalid -minver " << _min_keep_versions << "\n";
return false;
}
if (_got_max_keep_days) {
if (_max_keep_days < _min_keep_days) {
nout
<< "-maxage " << _max_keep_days << " is less than -minage "
<< _min_keep_days << "\n";
return false;
}
}
if (_got_max_keep_versions) {
if (_max_keep_versions < _min_keep_versions) {
nout
<< "-maxver " << _max_keep_versions << " is less than -minver "
<< _min_keep_versions << "\n";
return false;
}
}
_now = HTTPDate::now();
if (_got_max_keep_days) {
_max_keep_date = _now - (time_t)(_max_keep_days * seconds_per_day);
}
_min_keep_date = _now - (time_t)(_min_keep_days * seconds_per_day);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: HTTPBackup::dispatch_url
// Access: Protected, Static
// Description: Dispatch function for a URL parameter.
////////////////////////////////////////////////////////////////////
bool HTTPBackup::
dispatch_url(const string &opt, const string &arg, void *var) {
URLSpec *up = (URLSpec *)var;
URLSpec new_url(arg);
(*up) = new_url;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: HTTPBackup::run
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void HTTPBackup::
run() {
// Output the current date and time in GMT, for logging.
nout << _now.get_string() << "\n";
// First, read in the catalog.
_catalog_name.set_text();
if (!_catalog_name.exists()) {
nout << _catalog_name << " does not yet exist.\n";
} else {
if (!_catalog.read(_catalog_name)) {
nout << "Unable to read " << _catalog_name << ".\n";
exit(1);
}
}
if (_got_check_days) {
// We're only checking the date of the latest download.
BackupCatalog::Entries &entries = _catalog._table[_document_name];
if (entries.empty()) {
nout << "No previous downloads for " << _document_name << ".\n";
exit(1);
}
BackupCatalog::Entry *latest = entries[entries.size() - 1];
int diff_secs = _now - latest->get_date();
double diff_days = (double)diff_secs / (double)seconds_per_day;
nout << "Most recent at " << latest->get_date().get_string()
<< ", " << diff_days << " days old.\n";
if (diff_days <= _check_days) {
nout << "OK.\n";
} else {
nout << "Too old!\n";
exit(1);
}
} else {
// Try to do the download.
// Now try to fetch the document.
if (!fetch_latest()) {
nout << "Errors while processing latest.\n";
exit(1);
}
if (!cleanup_old()) {
nout << "Errors while cleaning up old versions.\n";
// We don't bother to exit the program in this case.
}
if (_catalog._dirty) {
// Now write out the modified catalog.
nout << "Writing " << _catalog_name << "\n";
_catalog_name.make_dir();
if (!_catalog.write(_catalog_name)) {
nout << "Unable to rewrite " << _catalog_name << ".\n";
exit(1);
}
}
}
}
////////////////////////////////////////////////////////////////////
// Function: HTTPBackup::fetch_latest
// Access: Private
// Description: Tries to get the latest version of the document from
// the server, if there is one available. Returns true
// on success (even if the most recent document hasn't
// changed), or false if there was some error.
////////////////////////////////////////////////////////////////////
bool HTTPBackup::
fetch_latest() {
// Check the most recent version of this document.
BackupCatalog::Entries &entries = _catalog._table[_document_name];
DocumentSpec document_spec(_url);
if (!entries.empty()) {
BackupCatalog::Entry *latest = entries[entries.size() - 1];
document_spec = latest->_document_spec;
document_spec.set_url(_url);
if (!document_spec.has_date()) {
// If we didn't get a last-modified date, use the download date
// instead.
document_spec.set_date(latest->get_date());
}
if (!_always_download) {
document_spec.set_request_mode(DocumentSpec::RM_newer);
}
}
// Since the purpose of this program is to check to see if a more
// recent document is available, we probably always want any proxies
// in the way to revalidate their cache.
document_spec.set_cache_control(DocumentSpec::CC_revalidate);
if (document_spec.get_request_mode() == DocumentSpec::RM_newer &&
document_spec.has_date()) {
nout << "Checking for newer than "<< document_spec.get_date().get_string()
<< ".\n";
}
nout << "Fetching " << document_spec.get_url() << "\n";
PT(HTTPChannel) channel = _http.make_channel(true);
if (_always_download) {
channel->get_document(document_spec);
} else {
// Start out by asking for the header first, so we can verify the
// document has changed before we try to download it again.
channel->get_header(document_spec);
}
if (!channel->is_valid()) {
if (channel->get_status_code() == 304) {
nout << "Document has not been modified.\n";
// This is considered a success condition.
return true;
}
nout << "Error fetching document: " << channel->get_status_code()
<< " " << channel->get_status_string() << "\n";
return false;
}
// The document is available.
if (!_always_download) {
if (!entries.empty()) {
// Has it been modified? We need to check again because the
// If-None-Match fields, etc. might have been ignored (e.g. by a
// proxy).
if (document_spec == channel->get_document_spec()) {
nout
<< "Document has not been modified (server ignored conditional request).\n";
return true;
}
}
// Ok, the document really is ready. Go ahead and download it.
if (!channel->get_document(document_spec)) {
nout << "Unable to request document.\n";
return false;
}
}
// We've started to download the document. Create an entry for it.
BackupCatalog::Entry *entry = new BackupCatalog::Entry;
entry->_document_name = _document_name;
entry->_document_spec = channel->get_document_spec();
entry->_download_date = _now;
// Generate a filename based on the last-modified date or the
// download date.
time_t time = entry->get_date().get_time();
struct tm *tp = gmtime(&time);
static const int buffer_size = 512;
char buffer[buffer_size];
if (strftime(buffer, buffer_size, _version_append.c_str(), tp) == 0) {
buffer[0] = '\0';
}
string filename = _document_name + string(buffer);
// Check the filename for uniqueness, just for good measure.
check_unique(filename);
entry->_filename = filename;
// Download to the indicated filename.
Filename pathname(_dirname, filename);
nout << "Downloading to " << pathname << "\n";
pathname.make_dir();
if (!channel->download_to_file(pathname)) {
nout << "Error while downloading.\n";
delete entry;
return false;
}
// The file is successfully downloaded; save the entry.
entries.push_back(entry);
_catalog._dirty = true;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: HTTPBackup::cleanup_old
// Access: Private
// Description: Removes old versions that are no longer needed.
////////////////////////////////////////////////////////////////////
bool HTTPBackup::
cleanup_old() {
BackupCatalog::Entries &entries = _catalog._table[_document_name];
if (_got_max_keep_versions &&
(int)entries.size() > _max_keep_versions) {
// Too many versions; delete the oldest ones, except those newer
// than min_keep_date.
int num_delete = entries.size() - _max_keep_versions;
while (num_delete > 0 && entries[num_delete - 1]->get_date() > _min_keep_date) {
num_delete--;
}
for (int i = 0; i < num_delete; i++) {
entries[i]->delete_file(_dirname, "too many old versions");
delete entries[i];
}
entries.erase(entries.begin(), entries.begin() + num_delete);
_catalog._dirty = true;
}
if (_got_max_keep_days &&
(int)entries.size() > _min_keep_versions &&
entries[0]->get_date() < _max_keep_date) {
// The oldest version is too old; delete all the oldest ones,
// but keep at least min_keep_versions of them around.
int num_delete = 1;
while (num_delete < (int)entries.size() - _min_keep_versions &&
entries[num_delete]->get_date() < _max_keep_date) {
num_delete++;
}
for (int i = 0; i < num_delete; i++) {
entries[i]->delete_file(_dirname, "too old");
delete entries[i];
}
entries.erase(entries.begin(), entries.begin() + num_delete);
_catalog._dirty = true;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: HTTPBackup::check_unique
// Access: Private
// Description: Ensures that the given filename is unique among all
// files in the catalog.
////////////////////////////////////////////////////////////////////
void HTTPBackup::
check_unique(string &filename) {
bool inserted = _catalog._filenames.insert(filename).second;
if (!inserted) {
// Conflict; append one or more letters to the filename until it
// is unique.
unsigned int uniquifier = 1;
string orig_filename = filename;
orig_filename += '.';
while (!inserted) {
filename = orig_filename;
unsigned int count = uniquifier;
while (count > 0) {
char ch = (char)((count % 26) + 'a');
filename += ch;
count /= 26;
}
uniquifier++;
inserted = _catalog._filenames.insert(filename).second;
}
}
}
int
main(int argc, char *argv[]) {
HTTPBackup prog;
prog.parse_command_line(argc, argv);
prog.run();
return 0;
}

View File

@ -1,84 +0,0 @@
// Filename: httpBackup.h
// Created by: drose (29Jan03)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef HTTPBACKUP_H
#define HTTPBACKUP_H
#include "pandaappbase.h"
#include "programBase.h"
#include "backupCatalog.h"
#include "httpClient.h"
#include "urlSpec.h"
////////////////////////////////////////////////////////////////////
// Class : HTTPBackup
// Description : This program is designed to run periodically as a
// background task, e.g. via a cron job. It fetches the
// latest copy of a document from an HTTP server and
// stores it, along with an optional number of previous
// versions, in a local directory so that it may be
// backed up to tape.
//
// If the copy on disk is already the same as the latest
// copy available on the HTTP server, this program does
// nothing.
////////////////////////////////////////////////////////////////////
class HTTPBackup : public ProgramBase {
public:
HTTPBackup();
protected:
virtual bool handle_args(Args &args);
virtual bool post_command_line();
static bool dispatch_url(const string &opt, const string &arg, void *var);
public:
void run();
private:
bool fetch_latest();
bool cleanup_old();
void check_unique(string &filename);
private:
string _proxy;
bool _got_proxy;
URLSpec _url;
Filename _dirname;
Filename _catalog_name;
string _document_name;
string _version_append;
bool _always_download;
double _max_keep_days;
bool _got_max_keep_days;
double _min_keep_days;
int _max_keep_versions;
bool _got_max_keep_versions;
int _min_keep_versions;
double _check_days;
bool _got_check_days;
HTTPDate _max_keep_date;
HTTPDate _min_keep_date;
HTTPDate _now;
HTTPClient _http;
BackupCatalog _catalog;
};
#endif

View File

@ -1,38 +0,0 @@
#define BUILD_DIRECTORY $[HAVE_FREETYPE]
#define OTHER_LIBS \
progbase pandatoolbase \
dtoolutil:c dtool:m prc:c dtoolbase:c dtoolconfig:m \
express:c pandaexpress:m \
putil:c pipeline:c linmath:c pnmimage:c mathutil:c pnmtext:c \
pnmimagetypes:c event:c panda:m \
pystub
#define UNIX_SYS_LIBS dl
#begin bin_target
#define USE_PACKAGES freetype
#define TARGET indexify
#define SOURCES \
default_index_icons.cxx default_index_icons.h \
default_font.cxx default_font.h \
indexImage.cxx indexImage.h \
indexParameters.cxx indexParameters.h \
indexify.cxx indexify.h \
photo.cxx photo.h \
rollDirectory.cxx rollDirectory.h
#end bin_target
#begin bin_target
#define USE_PACKAGES freetype
#define TARGET font-samples
#define SOURCES \
default_font.cxx default_font.h \
fontSamples.cxx fontSamples.h
#end bin_target

File diff suppressed because it is too large Load Diff

View File

@ -1,22 +0,0 @@
// Filename: default_font.h
// Created by: drose (04Apr02)
//
////////////////////////////////////////////////////////////////////
///
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef DEFAULT_FONT_H
#define DEFAULT_FONT_H
extern const unsigned char default_font[];
extern const int default_font_size;
#endif

View File

@ -1,297 +0,0 @@
// Filename: default_index_icons.cxx
// Created by: drose (04Apr02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "default_index_icons.h"
// This file was generated from left.png, right.png, up.png,
// movie.png, and sound.png; it provides data for default icons if the
// -i parameter is supplied on the command line.
const char *default_left_icon_filename = "left.png";
const char *default_right_icon_filename = "right.png";
const char *default_up_icon_filename = "up.png";
const char *default_movie_icon_filename = "movie.png";
const char *default_sound_icon_filename = "sound.png";
/*
Use this series of commands to regenerate the tables:
bin2c -n default_left_icon left.png >> default_index_icons.cxx
bin2c -n default_right_icon right.png >> default_index_icons.cxx
bin2c -n default_up_icon up.png >> default_index_icons.cxx
bin2c -n default_movie_icon movie.png >> default_index_icons.cxx
bin2c -n default_sound_icon sound.png >> default_index_icons.cxx
*/
/*
* This table was generated by the command:
*
* bin2c -n default_left_icon left.png
*/
const unsigned char default_left_icon[] = {
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00,
0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
0x00, 0x1e, 0x08, 0x03, 0x00, 0x00, 0x00, 0x0c, 0xee, 0x5e, 0x90,
0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1,
0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x2d, 0x50, 0x4c,
0x54, 0x45, 0xeb, 0xed, 0xee, 0xdd, 0xe1, 0xe3, 0xcf, 0xd4, 0xd7,
0xc2, 0xc9, 0xcd, 0xb5, 0xbd, 0xc2, 0xae, 0xb7, 0xbc, 0xa7, 0xb0,
0xb6, 0x99, 0xa4, 0xab, 0x8c, 0x98, 0xa0, 0x7e, 0x8c, 0x95, 0x77,
0x86, 0x8f, 0x6c, 0x7a, 0x83, 0x60, 0x6c, 0x74, 0x55, 0x60, 0x67,
0x4f, 0x5a, 0x60, 0x44, 0x10, 0xa7, 0xee, 0x00, 0x00, 0x01, 0x96,
0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x7d, 0x93, 0xdd, 0x92, 0xec,
0x20, 0x08, 0x84, 0x47, 0x7e, 0x04, 0xd4, 0xe4, 0xfd, 0x1f, 0xf7,
0x74, 0xe3, 0x9c, 0xaa, 0xbd, 0xd8, 0x5a, 0x2f, 0x66, 0x12, 0x3f,
0x81, 0xb6, 0x21, 0x9f, 0xcf, 0x2f, 0x4b, 0xe4, 0xfb, 0x70, 0x7e,
0xa3, 0x9f, 0x31, 0xee, 0xff, 0x24, 0x56, 0x15, 0x8b, 0xa9, 0x63,
0x08, 0x96, 0xe9, 0xf8, 0x0c, 0x35, 0x9f, 0xa6, 0xa2, 0xb5, 0x89,
0x45, 0x67, 0xba, 0xca, 0x10, 0x33, 0x73, 0x13, 0x9c, 0x53, 0x2e,
0xb3, 0x45, 0x6c, 0x86, 0x27, 0x1c, 0xc6, 0x29, 0x47, 0x26, 0xe2,
0x7e, 0x33, 0xad, 0x02, 0x8e, 0x00, 0x9d, 0xd3, 0xb8, 0x21, 0x0c,
0x14, 0x3b, 0xce, 0x42, 0xa3, 0x16, 0x05, 0x4c, 0x77, 0xc7, 0x19,
0x60, 0x63, 0xca, 0xb9, 0x9f, 0x07, 0x69, 0x20, 0x26, 0xd7, 0x95,
0xa6, 0xea, 0xdc, 0x40, 0x65, 0xf3, 0x7a, 0xdf, 0xe7, 0xa0, 0x1e,
0xb4, 0xcc, 0x6c, 0x69, 0x54, 0x3c, 0xad, 0x57, 0x3e, 0x58, 0xa7,
0xb1, 0x68, 0x54, 0x47, 0xb3, 0xa4, 0xff, 0x80, 0x7b, 0xb7, 0x46,
0xcd, 0xfc, 0x62, 0xe4, 0x45, 0x81, 0xf3, 0x36, 0x5c, 0x6b, 0x07,
0x6f, 0xe6, 0x19, 0xc4, 0x14, 0x84, 0x3b, 0xd5, 0x83, 0xa2, 0x7b,
0xef, 0xca, 0x5c, 0xd1, 0x2a, 0xcf, 0xba, 0xf7, 0x86, 0xde, 0x42,
0xda, 0xf7, 0x41, 0x64, 0x55, 0x56, 0x39, 0xb2, 0x89, 0x1e, 0x9a,
0xea, 0x6e, 0x1a, 0xcc, 0x4b, 0x0c, 0x08, 0xba, 0x9c, 0x29, 0x75,
0x37, 0x06, 0x7d, 0xbb, 0xea, 0x73, 0x16, 0x28, 0x70, 0xb5, 0x91,
0xd6, 0xd1, 0xbc, 0x17, 0xac, 0xa0, 0x60, 0x64, 0x66, 0x74, 0x26,
0x5d, 0xd6, 0x9b, 0x9c, 0x1d, 0x10, 0x49, 0x62, 0x42, 0xe2, 0x0a,
0x52, 0x59, 0xed, 0x1a, 0xcc, 0x62, 0xae, 0xd8, 0x0c, 0xcf, 0x3e,
0x10, 0x74, 0xf2, 0xde, 0xdb, 0x33, 0xd9, 0x14, 0x38, 0x57, 0x67,
0xdf, 0xec, 0x3b, 0x18, 0xe0, 0xbb, 0x5b, 0x12, 0xc0, 0xd7, 0xd9,
0x80, 0xe8, 0x95, 0x51, 0x3b, 0x69, 0xe2, 0xad, 0xad, 0x16, 0x41,
0xda, 0xdd, 0x44, 0x85, 0x8a, 0x2c, 0x36, 0xd1, 0xa4, 0x1b, 0x0a,
0xbf, 0x1d, 0xed, 0x61, 0x13, 0xc4, 0xdc, 0x29, 0x3c, 0x31, 0x4d,
0xae, 0x63, 0x4e, 0x46, 0x63, 0xb0, 0xe4, 0x36, 0x5b, 0x67, 0xc0,
0xfb, 0xeb, 0x1a, 0x42, 0x26, 0x3d, 0x97, 0x89, 0xdc, 0x18, 0x17,
0x12, 0x4e, 0x05, 0x86, 0x6a, 0xb9, 0xd0, 0xd5, 0x6c, 0x5b, 0xa8,
0x0b, 0xd9, 0x48, 0xfa, 0xc7, 0xfe, 0xcf, 0xe5, 0x6a, 0x7c, 0x27,
0x8c, 0x9b, 0x82, 0xa1, 0x31, 0xef, 0xa9, 0x1e, 0xa8, 0xb9, 0xf7,
0xd7, 0xd4, 0x56, 0xae, 0x2d, 0xa0, 0xa7, 0xb2, 0xa5, 0x7e, 0x3d,
0xff, 0x33, 0x7a, 0xf6, 0x45, 0xe1, 0xdc, 0x84, 0x3a, 0x98, 0xb6,
0xcf, 0xc2, 0x0b, 0xac, 0xa1, 0x03, 0xf8, 0xcc, 0xce, 0x69, 0xa3,
0x89, 0xc9, 0xd1, 0x9a, 0xc0, 0x73, 0x9e, 0x8d, 0xad, 0x7f, 0xbd,
0xcf, 0x11, 0xe9, 0xc6, 0x04, 0xc1, 0x3d, 0x00, 0x00, 0x00, 0x00,
0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
const int default_left_icon_len = 536;
/*
* This table was generated by the command:
*
* bin2c -n default_right_icon right.png
*/
const unsigned char default_right_icon[] = {
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00,
0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
0x00, 0x1e, 0x08, 0x03, 0x00, 0x00, 0x00, 0x0c, 0xee, 0x5e, 0x90,
0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1,
0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x2d, 0x50, 0x4c,
0x54, 0x45, 0xec, 0xee, 0xef, 0xd8, 0xdc, 0xdf, 0xca, 0xd0, 0xd3,
0xc3, 0xc9, 0xcd, 0xae, 0xb7, 0xbc, 0xa8, 0xb1, 0xb7, 0x99, 0xa4,
0xab, 0x93, 0x9f, 0xa6, 0x86, 0x93, 0x9b, 0x77, 0x86, 0x8f, 0x71,
0x80, 0x89, 0x60, 0x6c, 0x74, 0x5b, 0x67, 0x6e, 0x50, 0x5b, 0x61,
0x45, 0x4e, 0x53, 0xeb, 0x64, 0x46, 0x0c, 0x00, 0x00, 0x01, 0x8c,
0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6d, 0x92, 0x59, 0x6e, 0xc3,
0x30, 0x0c, 0x44, 0x2d, 0x71, 0x95, 0x94, 0xf4, 0xfe, 0xc7, 0xed,
0xcc, 0xc8, 0x40, 0x7f, 0x4a, 0x04, 0x89, 0xc3, 0xc7, 0x65, 0x4c,
0xf2, 0x79, 0xfe, 0xb1, 0x39, 0xde, 0x87, 0xf3, 0xfc, 0x6b, 0x2f,
0x0e, 0xe2, 0x69, 0xd3, 0x6c, 0xce, 0x31, 0xf8, 0xc1, 0xef, 0x33,
0x3c, 0x33, 0xc3, 0xe7, 0x58, 0x1b, 0x18, 0xc8, 0x33, 0x8c, 0x6c,
0x20, 0x14, 0x99, 0xd3, 0x3d, 0x1c, 0x6e, 0x61, 0x64, 0x44, 0x05,
0x53, 0xdd, 0xcd, 0x6d, 0xa8, 0xde, 0x44, 0x45, 0x5b, 0x0d, 0x0c,
0xa7, 0x79, 0x7d, 0x62, 0x98, 0x52, 0xc6, 0x20, 0x1e, 0xc2, 0x0b,
0x38, 0x13, 0xbc, 0x7f, 0xbe, 0x1b, 0x71, 0x72, 0x8f, 0x71, 0x45,
0x8c, 0x22, 0x8e, 0x70, 0xf7, 0xf5, 0xf3, 0xfd, 0x7c, 0xda, 0x21,
0x03, 0x32, 0x81, 0xf9, 0xfd, 0x44, 0xdf, 0xde, 0xd3, 0xfa, 0xfb,
0x39, 0xb0, 0x36, 0xbe, 0x86, 0x5d, 0x8d, 0x23, 0x97, 0x94, 0xa3,
0x56, 0x01, 0xef, 0x7d, 0xce, 0x4e, 0x89, 0x12, 0xb6, 0x62, 0xb6,
0xa2, 0xf3, 0x0b, 0x4a, 0x3b, 0xcb, 0xe9, 0xa0, 0x78, 0xeb, 0x7c,
0x31, 0xb2, 0xcf, 0x5e, 0xb2, 0x7d, 0xca, 0x5c, 0x21, 0x7e, 0x54,
0x9c, 0x73, 0xe9, 0xef, 0x21, 0xeb, 0x06, 0xdf, 0xbb, 0x9d, 0x6f,
0xe1, 0xe7, 0xdc, 0x6c, 0xb3, 0x22, 0x86, 0xbf, 0x5a, 0x05, 0x76,
0x72, 0x04, 0xfb, 0xdc, 0xb1, 0xcc, 0x99, 0xc4, 0x50, 0x5e, 0x85,
0x02, 0x94, 0x90, 0xc8, 0x39, 0x17, 0x73, 0xac, 0x12, 0xbe, 0xbb,
0x6f, 0x7e, 0xb3, 0xf9, 0xc5, 0x9a, 0x91, 0x13, 0x93, 0xca, 0x5c,
0xe2, 0xa6, 0x86, 0xaa, 0x55, 0x09, 0xaf, 0x0b, 0xcb, 0x4c, 0x0d,
0x67, 0xd5, 0xa3, 0xf5, 0xf9, 0xed, 0xbd, 0x29, 0x9d, 0x4d, 0x45,
0xcd, 0x36, 0xb3, 0xbd, 0x2a, 0xa1, 0x9c, 0xaf, 0x8d, 0xfc, 0xd0,
0xfa, 0x5d, 0x31, 0xea, 0x1d, 0x59, 0xe9, 0xf9, 0x01, 0x5a, 0x2b,
0xe1, 0xc4, 0x34, 0x71, 0x2b, 0xec, 0xdd, 0x4b, 0xc5, 0x33, 0x2d,
0x0e, 0x87, 0x31, 0x4d, 0x58, 0x3f, 0x38, 0x8c, 0x08, 0x4a, 0xa3,
0x0b, 0xd2, 0x96, 0xf1, 0x5e, 0x5c, 0x1b, 0x9a, 0xce, 0x5b, 0x8b,
0x54, 0x36, 0x1e, 0xe3, 0x68, 0x4e, 0x91, 0x1c, 0x02, 0x37, 0xcc,
0x2a, 0xa5, 0x4b, 0x8d, 0xc4, 0x7c, 0x43, 0x04, 0x97, 0x83, 0xd6,
0xda, 0x18, 0x2f, 0xf5, 0x1e, 0xb2, 0xaa, 0x22, 0x68, 0x28, 0x92,
0x17, 0x39, 0x74, 0x6b, 0xfb, 0xbd, 0xd4, 0xa1, 0x6a, 0x8a, 0x82,
0xaa, 0x0c, 0x1e, 0xbb, 0x79, 0xfc, 0x0d, 0xf5, 0x35, 0xd2, 0x08,
0x5d, 0x1b, 0x12, 0x98, 0x1d, 0x7b, 0x65, 0x61, 0x53, 0x19, 0x68,
0xcf, 0x75, 0x9f, 0x85, 0x3f, 0xa9, 0xb5, 0x43, 0xf9, 0xd1, 0x1a,
0xab, 0x89, 0xc9, 0x79, 0x6f, 0x78, 0x6e, 0xac, 0x2f, 0xe3, 0x17,
0x29, 0xef, 0x0f, 0xde, 0x36, 0xeb, 0x43, 0xec, 0x00, 0x00, 0x00,
0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
const int default_right_icon_len = 526;
/*
* This table was generated by the command:
*
* bin2c -n default_up_icon up.png
*/
const unsigned char default_up_icon[] = {
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00,
0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00,
0x00, 0x1e, 0x08, 0x03, 0x00, 0x00, 0x00, 0x0c, 0xee, 0x5e, 0x90,
0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1,
0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x2d, 0x50, 0x4c,
0x54, 0x45, 0xeb, 0xed, 0xee, 0xdd, 0xe1, 0xe3, 0xcf, 0xd4, 0xd7,
0xc9, 0xcf, 0xd2, 0xc2, 0xc9, 0xcd, 0xb4, 0xbc, 0xc1, 0xad, 0xb6,
0xbb, 0x98, 0xa3, 0xaa, 0x92, 0x9e, 0xa5, 0x7d, 0x8b, 0x94, 0x70,
0x7f, 0x88, 0x65, 0x72, 0x7a, 0x5f, 0x6b, 0x73, 0x54, 0x5f, 0x66,
0x4a, 0x53, 0x59, 0xac, 0xfc, 0xc3, 0x4d, 0x00, 0x00, 0x01, 0xa3,
0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6d, 0x53, 0x59, 0x96, 0xc3,
0x30, 0x08, 0x8b, 0x59, 0xbd, 0x90, 0xdc, 0xff, 0xb8, 0x23, 0xe1,
0x7e, 0x0e, 0xaf, 0x75, 0x5a, 0x8b, 0x45, 0x02, 0xf2, 0x3c, 0xff,
0x98, 0xc8, 0xef, 0x47, 0xfd, 0x87, 0x3e, 0x63, 0xdc, 0x67, 0x10,
0x16, 0x53, 0x33, 0x15, 0x19, 0xfc, 0xa8, 0x8c, 0x21, 0x9e, 0x99,
0xe1, 0x22, 0xeb, 0x00, 0x06, 0xe4, 0x19, 0x86, 0x6b, 0x98, 0xeb,
0x78, 0x86, 0x7a, 0x84, 0x9b, 0xe8, 0xde, 0x80, 0x55, 0x34, 0x66,
0x20, 0x4c, 0xdc, 0x1d, 0x41, 0xf0, 0x33, 0x55, 0x35, 0xf7, 0xb5,
0x00, 0xbb, 0x9b, 0x7f, 0xdf, 0xf7, 0xbe, 0x6f, 0x1f, 0x3f, 0x13,
0x73, 0x5b, 0x8c, 0xce, 0xf4, 0x86, 0xeb, 0x7d, 0xeb, 0x9c, 0x2a,
0x1c, 0x78, 0xa0, 0xd0, 0x98, 0x84, 0x03, 0x46, 0xf8, 0xb4, 0x11,
0xdc, 0xfb, 0x1c, 0xd3, 0x31, 0x62, 0xb2, 0x36, 0x8a, 0x5b, 0x04,
0xf8, 0xa3, 0xb2, 0x3b, 0x1e, 0x26, 0xa2, 0xe0, 0x20, 0xc9, 0xda,
0xd6, 0x8c, 0x89, 0xc0, 0x20, 0xb1, 0x71, 0xc0, 0x62, 0x93, 0xd1,
0x66, 0x70, 0xb0, 0x0b, 0xaf, 0xa9, 0x74, 0x71, 0xf8, 0x10, 0xce,
0x1f, 0x0c, 0xa5, 0x06, 0xc0, 0xab, 0x80, 0x41, 0x68, 0xe0, 0x52,
0xa3, 0x48, 0x8d, 0xbe, 0xe8, 0x83, 0x22, 0xc3, 0x79, 0x6b, 0xb1,
0x81, 0x2c, 0x05, 0xf7, 0xaa, 0xab, 0x1b, 0x2d, 0x00, 0xec, 0x1b,
0xea, 0xaa, 0x39, 0xe2, 0x3f, 0x52, 0x9e, 0x6a, 0x61, 0xde, 0x74,
0xd4, 0x5b, 0xdd, 0x62, 0x2a, 0x04, 0x20, 0xfd, 0x85, 0x1d, 0xca,
0x40, 0xc4, 0xd7, 0xf7, 0x15, 0x34, 0xa3, 0x4b, 0x24, 0xd3, 0x4c,
0x7a, 0xba, 0x72, 0xa5, 0x31, 0x78, 0xc3, 0xbc, 0xd3, 0x83, 0x5b,
0x8f, 0x04, 0x53, 0xec, 0x60, 0x56, 0xde, 0x7b, 0xad, 0x3d, 0xc9,
0x05, 0xfa, 0xa5, 0x75, 0xa3, 0x96, 0x33, 0xd7, 0xc7, 0x9e, 0xaf,
0x35, 0xd7, 0xbe, 0xc4, 0xcc, 0x3a, 0x3a, 0xe6, 0x44, 0x39, 0x87,
0x28, 0x54, 0x5e, 0xc4, 0x17, 0x96, 0x81, 0x62, 0xba, 0x76, 0x24,
0x60, 0x4b, 0x8e, 0x6b, 0x13, 0x9b, 0x73, 0xcf, 0xe8, 0xee, 0xf7,
0x40, 0x15, 0xbb, 0x63, 0x52, 0x28, 0x7c, 0x43, 0x67, 0x22, 0x3d,
0xa6, 0xe8, 0x12, 0xd1, 0xbb, 0x16, 0x21, 0xf3, 0x25, 0x3c, 0xe9,
0x00, 0x43, 0x76, 0xb4, 0x71, 0x04, 0x7b, 0xae, 0xcc, 0xf4, 0x36,
0xbc, 0x20, 0xab, 0xe1, 0x0d, 0x18, 0xeb, 0xd0, 0xba, 0x23, 0xcd,
0x79, 0x09, 0x82, 0x7d, 0x70, 0x3f, 0x8c, 0x5d, 0xde, 0x0d, 0x73,
0xfc, 0xb8, 0x4b, 0x8c, 0xb8, 0x0f, 0xca, 0xea, 0xbd, 0x3c, 0xa4,
0xc6, 0x8e, 0xb2, 0xe9, 0xb8, 0x94, 0x0e, 0x4b, 0x94, 0x1d, 0x03,
0x8c, 0xea, 0xfc, 0x9a, 0xaa, 0xfc, 0x2a, 0x3b, 0x6d, 0xdc, 0xf1,
0x7e, 0x21, 0x6e, 0x74, 0xec, 0x95, 0x13, 0x7c, 0x49, 0x36, 0xc1,
0x1c, 0xea, 0xf1, 0x27, 0xc9, 0x72, 0xe5, 0x83, 0xc5, 0xad, 0x16,
0x43, 0x98, 0x78, 0xd5, 0xc6, 0x2b, 0x14, 0xf3, 0x1c, 0x5c, 0xfd,
0x01, 0x56, 0x35, 0x13, 0x9e, 0xbd, 0x4e, 0x62, 0x4e, 0x00, 0x00,
0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
const int default_up_icon_len = 549;
/*
* This table was generated by the command:
*
* bin2c -n default_movie_icon movie.png
*/
const unsigned char default_movie_icon[] = {
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00,
0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00,
0x00, 0x16, 0x04, 0x03, 0x00, 0x00, 0x00, 0x32, 0x6f, 0xa1, 0x35,
0x00, 0x00, 0x00, 0x15, 0x50, 0x4c, 0x54, 0x45, 0xcc, 0xff, 0xff,
0xff, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x99, 0x99, 0x99, 0x66, 0x66,
0x66, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, 0x89, 0x10, 0x3a, 0x6d,
0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, 0x06, 0x61, 0x66,
0xb8, 0x7d, 0x00, 0x00, 0x00, 0x39, 0x49, 0x44, 0x41, 0x54, 0x78,
0xda, 0x63, 0x48, 0x83, 0x82, 0x04, 0x06, 0x86, 0x24, 0x35, 0x30,
0x4b, 0x29, 0x15, 0xc4, 0x74, 0x01, 0x02, 0x31, 0x10, 0x33, 0x2d,
0xcd, 0xd9, 0xd8, 0xd8, 0x58, 0x2c, 0x0d, 0x2c, 0x0a, 0x66, 0x2a,
0xa1, 0x32, 0x89, 0x50, 0x20, 0x08, 0x04, 0x50, 0x05, 0xf4, 0xb5,
0x02, 0xce, 0x64, 0x0d, 0x85, 0x02, 0x06, 0x00, 0x66, 0x25, 0x34,
0xea, 0x21, 0xc4, 0xeb, 0x5e, 0x00, 0x00, 0x00, 0x56, 0x74, 0x45,
0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x54,
0x68, 0x69, 0x73, 0x20, 0x61, 0x72, 0x74, 0x20, 0x69, 0x73, 0x20,
0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x75, 0x62, 0x6c,
0x69, 0x63, 0x20, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x20,
0x4b, 0x65, 0x76, 0x69, 0x6e, 0x20, 0x48, 0x75, 0x67, 0x68, 0x65,
0x73, 0x2c, 0x20, 0x6b, 0x65, 0x76, 0x69, 0x6e, 0x68, 0x40, 0x65,
0x69, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x20, 0x53, 0x65, 0x70,
0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x31, 0x39, 0x39, 0x35,
0x4c, 0xe8, 0xf4, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e,
0x44, 0xae, 0x42, 0x60, 0x82
};
const int default_movie_icon_len = 258;
/*
* This table was generated by the command:
*
* bin2c -n default_sound_icon sound.png
*/
const unsigned char default_sound_icon[] = {
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00,
0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00,
0x00, 0x16, 0x04, 0x03, 0x00, 0x00, 0x00, 0x32, 0x6f, 0xa1, 0x35,
0x00, 0x00, 0x00, 0x18, 0x50, 0x4c, 0x54, 0x45, 0xcc, 0xff, 0xff,
0xff, 0x33, 0x33, 0xff, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x99, 0x99,
0x99, 0x66, 0x00, 0x00, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, 0xfd,
0xef, 0xcf, 0xe1, 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44,
0x07, 0x16, 0x61, 0x88, 0xeb, 0x00, 0x00, 0x00, 0x6a, 0x49, 0x44,
0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0xc0, 0x0d, 0x12, 0x18, 0x18,
0x05, 0x20, 0x2c, 0xf6, 0x02, 0x41, 0x06, 0x41, 0x08, 0xb3, 0xa4,
0x80, 0x51, 0x00, 0x22, 0xcc, 0xee, 0x54, 0xc0, 0x20, 0x08, 0x61,
0x96, 0x28, 0x15, 0x08, 0x30, 0x02, 0x55, 0xb0, 0x97, 0x97, 0x3b,
0x29, 0x15, 0x00, 0x05, 0x03, 0x19, 0x4a, 0x5c, 0x5c, 0x94, 0x80,
0x4c, 0x56, 0x10, 0x53, 0x09, 0x08, 0x0a, 0x02, 0x89, 0x63, 0xa6,
0xa4, 0x24, 0x41, 0xb5, 0x01, 0x0d, 0x33, 0x83, 0x1a, 0xc6, 0x90,
0x96, 0x56, 0x9c, 0x04, 0xb1, 0x02, 0x08, 0xd2, 0xcd, 0xe0, 0x16,
0xb3, 0x15, 0x83, 0x9c, 0x03, 0x71, 0x59, 0x3a, 0xc2, 0x91, 0x6c,
0x08, 0xa7, 0x63, 0x00, 0x00, 0xac, 0x1b, 0x1b, 0xa7, 0x07, 0x45,
0x3c, 0x76, 0x00, 0x00, 0x00, 0x56, 0x74, 0x45, 0x58, 0x74, 0x43,
0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x54, 0x68, 0x69, 0x73,
0x20, 0x61, 0x72, 0x74, 0x20, 0x69, 0x73, 0x20, 0x69, 0x6e, 0x20,
0x74, 0x68, 0x65, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20,
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x20, 0x4b, 0x65, 0x76,
0x69, 0x6e, 0x20, 0x48, 0x75, 0x67, 0x68, 0x65, 0x73, 0x2c, 0x20,
0x6b, 0x65, 0x76, 0x69, 0x6e, 0x68, 0x40, 0x65, 0x69, 0x74, 0x2e,
0x63, 0x6f, 0x6d, 0x2c, 0x20, 0x53, 0x65, 0x70, 0x74, 0x65, 0x6d,
0x62, 0x65, 0x72, 0x20, 0x31, 0x39, 0x39, 0x35, 0x4c, 0xe8, 0xf4,
0xc4, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42,
0x60, 0x82
};
const int default_sound_icon_len = 310;

View File

@ -1,36 +0,0 @@
// Filename: default_index_icons.h
// Created by: drose (04Apr02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef DEFAULT_INDEX_ICONS_H
#define DEFAULT_INDEX_ICONS_H
extern const char *default_left_icon_filename;
extern const char *default_right_icon_filename;
extern const char *default_up_icon_filename;
extern const char *default_movie_icon_filename;
extern const char *default_sound_icon_filename;
extern const unsigned char default_left_icon[];
extern const int default_left_icon_len;
extern const unsigned char default_right_icon[];
extern const int default_right_icon_len;
extern const unsigned char default_up_icon[];
extern const int default_up_icon_len;
extern const unsigned char default_movie_icon[];
extern const int default_movie_icon_len;
extern const unsigned char default_sound_icon[];
extern const int default_sound_icon_len;
#endif

View File

@ -1,264 +0,0 @@
// Filename: fontSamples.cxx
// Created by: drose (03Apr02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "fontSamples.h"
#include "pnmTextMaker.h"
#include "default_font.h"
#include "pnmImage.h"
#include "pnotify.h"
#include <stdio.h>
#ifdef WIN32_VC
#define snprintf _snprintf
#endif
////////////////////////////////////////////////////////////////////
// Function: FontSamples::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
FontSamples::
FontSamples() {
clear_runlines();
add_runline("[opts] fontname [fontname ...]");
set_program_description
("Generates one or more image files with one line of text from "
"each of several given font files, as a font sample sheet.");
add_option
("t", "text", 0,
"Specifies the sample text to render using each font.",
&FontSamples::dispatch_string, NULL, &_sample_text);
add_option
("sh", "height", 0,
"Specifies the pixel height of each sample.",
&FontSamples::dispatch_int, NULL, &_sample_height);
add_option
("nf", "filename", 0,
"Specifies the filename of the font to be used to write each font's "
"name.",
&FontSamples::dispatch_filename, NULL, &_name_font_filename);
add_option
("nh", "height", 0,
"Specifies the pixel height of each font's name.",
&FontSamples::dispatch_int, NULL, &_name_height);
add_option
("fontaa", "factor", 0,
"Specifies a scale factor to apply to the fonts "
"for the purpose of antialiasing the fonts a "
"little better than FreeType can do by itself. The letters are "
"generated large and then scaled to their proper size. Normally this "
"should be a number in the range 3 to 4 for best effect.",
&FontSamples::dispatch_double, NULL, &_font_aa_factor);
add_option
("space", "y", 0,
"Specifies the vertical space in pixels between font samples.",
&FontSamples::dispatch_int, NULL, &_vert_space);
add_option
("image", "x, y", 0,
"Specifies the width and height in pixels of the resulting image(s).",
&FontSamples::dispatch_int_pair, NULL, &_image_width);
add_option
("o", "filename", 50,
"Specify the filename(s) to which the resulting image file will "
"be written. This should contain the string '%d' which will be "
"filled in with the index number of the particular frame.",
&FontSamples::dispatch_string, NULL, &_output_filename);
_sample_text = "The quick brown fox jumped over the lazy dog's back.";
_sample_height = 14;
_name_height = 10;
_font_aa_factor = 4.0;
_vert_space = 10;
_image_width = 600;
_image_height = 600;
_output_filename = "samples-%d.jpg";
_name_text_maker = (PNMTextMaker *)NULL;
}
////////////////////////////////////////////////////////////////////
// Function: FontSamples::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
FontSamples::
~FontSamples() {
if (_name_text_maker != (PNMTextMaker *)NULL) {
delete _name_text_maker;
}
}
////////////////////////////////////////////////////////////////////
// Function: FontSamples::handle_args
// Access: Protected, Virtual
// Description: Does something with the additional arguments on the
// command line (after all the -options have been
// parsed). Returns true if the arguments are good,
// false otherwise.
////////////////////////////////////////////////////////////////////
bool FontSamples::
handle_args(ProgramBase::Args &args) {
if (args.empty()) {
nout << "You must specify the font filenames on the command line.\n";
return false;
}
Args::const_iterator ai;
for (ai = args.begin(); ai != args.end(); ++ai) {
Filename filename = Filename::from_os_specific(*ai);
filename.standardize();
if (filename.exists()) {
_font_filenames.push_back(filename);
} else {
nout << filename << " does not exist.\n";
return false;
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: FontSamples::post_command_line
// Access: Protected, Virtual
// Description: This is called after the command line has been
// completely processed, and it gives the program a
// chance to do some last-minute processing and
// validation of the options and arguments. It should
// return true if everything is fine, false if there is
// an error.
////////////////////////////////////////////////////////////////////
bool FontSamples::
post_command_line() {
if (_font_filenames.empty()) {
nout << "No font filenames.\n";
return false;
}
if (_name_height != 0) {
if (!_name_font_filename.empty()) {
_name_text_maker = new PNMTextMaker(_name_font_filename, 0);
if (!_name_text_maker->is_valid()) {
delete _name_text_maker;
_name_text_maker = (PNMTextMaker *)NULL;
}
}
if (_name_text_maker == (PNMTextMaker *)NULL) {
_name_text_maker = new PNMTextMaker((const char *)default_font,
default_font_size, 0);
if (!_name_text_maker->is_valid()) {
nout << "Unable to open default font.\n";
delete _name_text_maker;
_name_text_maker = (PNMTextMaker *)NULL;
}
}
}
if (_name_text_maker != (PNMTextMaker *)NULL) {
_name_text_maker->set_scale_factor(_font_aa_factor);
_name_text_maker->set_pixel_size(_name_height);
} else {
_name_height = 0;
}
return ProgramBase::post_command_line();
}
////////////////////////////////////////////////////////////////////
// Function: FontSamples::run
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void FontSamples::
run() {
int output_index = 1;
PNMImage output_image(_image_width, _image_height, 1);
static const int output_filename_size = 1024;
char output_filename[output_filename_size];
bool all_ok = true;
output_image.fill(1, 1, 1);
int y = _vert_space;
int vert_per_font =
_sample_height + _name_height + _vert_space;
Filenames::iterator fi;
for (fi = _font_filenames.begin(); fi != _font_filenames.end(); ++fi) {
if (y > _image_height - vert_per_font) {
// Write out the current image.
snprintf(output_filename, output_filename_size,
_output_filename.c_str(), output_index);
nout << "Writing " << output_filename << "\n";
if (!output_image.write(output_filename)) {
nout << "Unable to write to " << output_filename << "\n";
exit(1);
}
output_index++;
output_image.fill(1, 1, 1);
y = _vert_space;
}
const Filename &filename = (*fi);
PNMTextMaker *text_maker = new PNMTextMaker(filename, 0);
if (!text_maker->is_valid()) {
all_ok = false;
} else {
text_maker->set_scale_factor(_font_aa_factor);
text_maker->set_pixel_size(_sample_height);
text_maker->generate_into(_sample_text, output_image,
16, y + _sample_height);
if (_name_text_maker != (PNMTextMaker *)NULL) {
string desc = filename.get_basename() + ": " + text_maker->get_name();
_name_text_maker->generate_into(desc, output_image,
16, y + _sample_height + _name_height);
}
}
y += vert_per_font;
delete text_maker;
}
snprintf(output_filename, output_filename_size,
_output_filename.c_str(), output_index);
nout << "Writing " << output_filename << "\n";
if (!output_image.write(output_filename)) {
nout << "Unable to write to " << output_filename << "\n";
exit(1);
}
if (!all_ok) {
nout << "Problem loading fonts.\n";
exit(1);
}
}
int main(int argc, char *argv[]) {
FontSamples prog;
prog.parse_command_line(argc, argv);
prog.run();
return 0;
}

View File

@ -1,59 +0,0 @@
// Filename: indexify.h
// Created by: drose (07Apr02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef FONTSAMPLES_H
#define FONTSAMPLES_H
#include "pandatoolbase.h"
#include "programBase.h"
#include "filename.h"
#include "pvector.h"
class PNMTextMaker;
////////////////////////////////////////////////////////////////////
// Class : FontSamples
// Description : A program to generate one or more image files showing
// samples of various fonts.
////////////////////////////////////////////////////////////////////
class FontSamples : public ProgramBase {
public:
FontSamples();
virtual ~FontSamples();
protected:
virtual bool handle_args(Args &args);
virtual bool post_command_line();
public:
void run();
string _sample_text;
int _sample_height;
int _name_height;
Filename _name_font_filename;
double _font_aa_factor;
int _vert_space;
int _image_width;
int _image_height;
string _output_filename;
typedef pvector<Filename> Filenames;
Filenames _font_filenames;
PNMTextMaker *_name_text_maker;
};
#endif

View File

@ -1,918 +0,0 @@
// Filename: indexImage.cxx
// Created by: drose (03Apr02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "indexImage.h"
#include "rollDirectory.h"
#include "photo.h"
#include "pnmTextMaker.h"
#include "indexParameters.h"
#include "pnmImage.h"
#include "pnmReader.h"
#include "string_utils.h"
////////////////////////////////////////////////////////////////////
// Function: IndexImage::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
IndexImage::
IndexImage(RollDirectory *dir, int index) :
_dir(dir),
_index(index)
{
_name = _dir->get_basename() + "_" + format_string(index + 1);
_index_x_size = 0;
_index_y_size = 0;
}
////////////////////////////////////////////////////////////////////
// Function: IndexImage::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
IndexImage::
~IndexImage() {
}
////////////////////////////////////////////////////////////////////
// Function: IndexImage::add_photo
// Access: Public
// Description: Adds the nth photo in the roll to the index image.
// Returns true if the photo is added, or false if there
// was no more room.
////////////////////////////////////////////////////////////////////
bool IndexImage::
add_photo(int photo_index) {
int count = _photos.size();
if (count >= max_thumbs) {
return false;
}
int yi = count / thumb_count_x;
int xi = count - (yi * thumb_count_x);
int x = thumb_x_space + xi * (thumb_width + thumb_x_space);
int y = thumb_y_space + yi * (thumb_height + thumb_caption_height + thumb_y_space);
PhotoInfo pinfo;
pinfo._photo_index = photo_index;
pinfo._x_place = x;
pinfo._y_place = y;
_photos.push_back(pinfo);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: IndexImage::generate_images
// Access: Public
// Description: Computes the thumbnail image file and writes it to
// the indicated directory; generates all reduced images
// associated with these photos into the appropriate
// subdirectory. Returns true on success, false on
// failure.
////////////////////////////////////////////////////////////////////
bool IndexImage::
generate_images(const Filename &archive_dir, PNMTextMaker *text_maker) {
int count = _photos.size();
int num_rows = (count + thumb_count_x - 1) / thumb_count_x;
int actual_index_height = thumb_y_space + num_rows * (thumb_height + thumb_caption_height + thumb_y_space);
PNMImage index_image;
Filename thumbnail_dir(archive_dir, "thumbs");
Filename output_filename(thumbnail_dir, _name);
output_filename.set_extension("jpg");
Photos::const_iterator pi;
// First, scan the image files to see if we can avoid regenerating
// the index image.
bool generate_index_image = true;
if (!dummy_mode && !force_regenerate && output_filename.exists()) {
// Maybe we don't need to renegerate the index.
generate_index_image = false;
const Filename &newest_contributing_filename =
_dir->get_newest_contributing_filename();
if (!newest_contributing_filename.empty()) {
generate_index_image =
(output_filename.compare_timestamps(newest_contributing_filename) < 0);
}
for (pi = _photos.begin();
pi != _photos.end() && !generate_index_image;
++pi) {
const PhotoInfo &pinfo = (*pi);
Photo *photo = _dir->get_photo(pinfo._photo_index);
Filename photo_filename(_dir->get_dir(), photo->get_basename());
// If any of the source photos are newer than the index image,
// we must regenerate it.
generate_index_image =
(output_filename.compare_timestamps(photo_filename) < 0);
}
}
// If we don't need to regenerate the index, we do need to at least
// scan the header.
if (!generate_index_image) {
if (index_image.read_header(output_filename)) {
if (index_image.get_x_size() != actual_index_width ||
index_image.get_y_size() != actual_index_height) {
// If the index exists but is the wrong size, we'd better
// regenerate it.
generate_index_image = true;
}
} else {
// If we couldn't even read the header, we'd better regenerate it
// after all.
nout << "Couldn't read " << output_filename << "; regenerating.\n";
generate_index_image = true;
}
}
if (generate_index_image) {
index_image.clear(actual_index_width, actual_index_height);
index_image.fill(1.0, 1.0, 1.0);
}
// Now go back through and read whichever images are necessary, or
// just read the headers if we can get away with it.
for (pi = _photos.begin(); pi != _photos.end(); ++pi) {
const PhotoInfo &pinfo = (*pi);
Photo *photo = _dir->get_photo(pinfo._photo_index);
PNMImage reduced_image;
if (!make_reduced_image(photo, reduced_image, generate_index_image, false)) {
return false;
}
if (generate_index_image) {
// Generate a thumbnail image for the photo.
PNMImage thumbnail_image;
compute_reduction(reduced_image, thumbnail_image,
thumb_interior_width, thumb_interior_height);
if (dummy_mode) {
draw_box(thumbnail_image);
} else {
thumbnail_image.quick_filter_from(reduced_image);
}
// Center the thumbnail image within its box.
int x_center = (thumb_width - thumbnail_image.get_x_size()) / 2;
int y_center = (thumb_height - thumbnail_image.get_y_size()) / 2;
if (draw_frames) {
draw_frame(index_image,
pinfo._x_place, pinfo._y_place,
thumb_width, thumb_height,
pinfo._x_place + x_center, pinfo._y_place + y_center,
thumbnail_image.get_x_size(), thumbnail_image.get_y_size());
}
thumbnail_image.set_color_type(index_image.get_color_type());
index_image.copy_sub_image(thumbnail_image,
pinfo._x_place + x_center,
pinfo._y_place + y_center);
if (text_maker != (PNMTextMaker *)NULL) {
int label_x = pinfo._x_place + thumb_width / 2;
int label_y = pinfo._y_place + thumb_height + thumb_caption_height;
int width =
text_maker->generate_into(photo->get_frame_number(), index_image,
label_x, label_y);
if (photo->_has_movie && get_movie_icon().is_valid()) {
const PNMImage &movie_icon_image = get_movie_icon();
int icon_x = label_x - width / 2 - movie_icon_image.get_x_size();
int icon_y = label_y - movie_icon_image.get_y_size();
index_image.blend_sub_image(movie_icon_image, icon_x, icon_y);
} else if (photo->_has_sound && get_sound_icon().is_valid()) {
const PNMImage &sound_icon_image = get_sound_icon();
int icon_x = label_x - width / 2 - sound_icon_image.get_x_size();
int icon_y = label_y - sound_icon_image.get_y_size();
index_image.blend_sub_image(sound_icon_image, icon_x, icon_y);
}
}
}
}
if (generate_index_image) {
nout << "Writing " << output_filename << "\n";
output_filename.make_dir();
if (!index_image.write(output_filename)) {
nout << "Unable to write.\n";
return false;
}
}
_index_x_size = index_image.get_x_size();
_index_y_size = index_image.get_y_size();
_index_basename = output_filename.get_basename();
return true;
}
////////////////////////////////////////////////////////////////////
// Function: IndexImage::make_reduced_image
// Access: Public
// Description: Copies the full-sized image to the reduced image
// folder, if necessary.
////////////////////////////////////////////////////////////////////
bool IndexImage::
make_reduced_image(Photo *photo, PNMImage &reduced_image,
bool generate_index_image, bool force_reduced) {
Filename reduced_dir(archive_dir, "reduced/" + _dir->get_basename());
Filename photo_filename(_dir->get_dir(), photo->get_basename());
Filename reduced_filename(reduced_dir, photo->get_basename());
photo_filename.standardize();
reduced_filename.standardize();
if (!dummy_mode && photo_filename != reduced_filename &&
(force_regenerate ||
reduced_filename.compare_timestamps(photo_filename) < 0)) {
// If the reduced filename does not exist or is older than the
// source filename, we must read the complete source filename to
// generate the reduced image.
PNMImage photo_image;
PNMReader *reader = photo_image.make_reader(photo_filename);
if (reader == (PNMReader *)NULL) {
nout << "Unable to read " << photo_filename << ".\n";
return false;
}
photo_image.copy_header_from(*reader);
photo->_full_x_size = photo_image.get_x_size();
photo->_full_y_size = photo_image.get_y_size();
// Generate a reduced image for the photo.
compute_reduction(photo_image, reduced_image,
reduced_width, reduced_height);
photo->_reduced_x_size = reduced_image.get_x_size();
photo->_reduced_y_size = reduced_image.get_y_size();
// Only bother making a reduced version if it would actually be
// smaller than the original.
if (photo->_reduced_x_size < photo->_full_x_size ||
photo->_reduced_y_size < photo->_full_y_size) {
nout << "Reading " << photo_filename << "\n";
if (!photo_image.read(reader)) {
nout << "Unable to read.\n";
return false;
}
reader = NULL;
reduced_image.quick_filter_from(photo_image);
reduced_filename.make_dir();
nout << "Writing " << reduced_filename << "\n";
if (!reduced_image.write(reduced_filename)) {
nout << "Unable to write.\n";
delete reader;
return false;
}
photo->_has_reduced = true;
} else if (force_reduced) {
// Even though the reduced image would not be smaller, copy it
// anyway when force_reduced is true.
photo_filename.set_binary();
if (!copy_file(photo_filename, reduced_dir)) {
return false;
}
} else {
// We're not making a reduced version. But maybe we still
// need to read the original so we can make a thumbnail.
reduced_filename = photo_filename;
reduced_image.copy_header_from(photo_image);
if (!dummy_mode && generate_index_image) {
nout << "Reading " << photo_filename << "\n";
if (!reduced_image.read(reader)) {
nout << "Unable to read image.\n";
return false;
}
reader = NULL;
}
}
if (reader != (PNMReader *)NULL) {
delete reader;
}
} else {
// If the reduced image already exists and is newer than the
// source image, use it.
if (!force_reduced) {
// We still read the image header to determine its size.
PNMImageHeader photo_image;
if (!photo_image.read_header(photo_filename)) {
nout << "Unable to read " << photo_filename << "\n";
return false;
}
photo->_full_x_size = photo_image.get_x_size();
photo->_full_y_size = photo_image.get_y_size();
photo->_has_reduced = true;
if (dummy_mode) {
// In dummy mode, we may or may not actually have a reduced
// image. In either case, ignore the file and compute its
// appropriate size from the source image.
compute_reduction(photo_image, reduced_image, reduced_width, reduced_height);
photo->_reduced_x_size = reduced_image.get_x_size();
photo->_reduced_y_size = reduced_image.get_y_size();
} else if (generate_index_image) {
// Now read the reduced image from disk, so we can put it on
// the index image.
nout << "Reading " << reduced_filename << "\n";
if (!reduced_image.read(reduced_filename)) {
nout << "Unable to read.\n";
return false;
}
photo->_reduced_x_size = reduced_image.get_x_size();
photo->_reduced_y_size = reduced_image.get_y_size();
} else {
// If we're not generating an index image, we don't even need
// the reduced image--just scan its header to get its size.
if (!reduced_image.read_header(reduced_filename)) {
nout << "Unable to read " << reduced_filename << "\n";
return false;
}
photo->_reduced_x_size = reduced_image.get_x_size();
photo->_reduced_y_size = reduced_image.get_y_size();
}
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: IndexImage::generate_html
// Access: Public
// Description: Generates all HTML files associated with reduced
// images into the appropriate subdirectory, and
// generates root-level HTML code to access the
// thumbnails on the index image into the indicated
// stream.
////////////////////////////////////////////////////////////////////
bool IndexImage::
generate_html(ostream &root_html, const Filename &archive_dir,
const Filename &roll_dir_root) {
root_html
<< "<a name=\"" << _name << "\">\n"
<< "<img src=\"../thumbs/" << _index_basename
<< "\" width=" << _index_x_size << " height=" << _index_y_size
<< " ismap usemap=\"#" << _name << "\">\n"
<< "<map name=\"" << _name << "\"><br>\n";
Filename html_dir(archive_dir, "html");
Photos::const_iterator pi;
for (pi = _photos.begin(); pi != _photos.end(); ++pi) {
const PhotoInfo &pinfo = (*pi);
int photo_index = pinfo._photo_index;
Photo *photo = _dir->get_photo(pinfo._photo_index);
Filename html_relname(_dir->get_basename(), photo->get_basename());
html_relname.set_extension("htm");
Filename html_filename(html_dir, html_relname);
html_filename.make_dir();
html_filename.set_text();
ofstream reduced_html;
if (!html_filename.open_write(reduced_html)) {
nout << "Unable to write to " << html_filename << "\n";
return false;
}
if (!generate_reduced_html(reduced_html, photo, photo_index,
pi - _photos.begin(), roll_dir_root)) {
return false;
}
root_html
<< " <area shape=\"RECT\" href=\"" << html_relname
<< "\" coords=\""
<< pinfo._x_place << "," << pinfo._y_place << ","
<< pinfo._x_place + thumb_width << ","
<< pinfo._y_place + thumb_height + thumb_caption_height
<< "\">\n";
}
root_html
<< "</map>\n";
return true;
}
////////////////////////////////////////////////////////////////////
// Function: IndexImage::copy_reduced
// Access: Public
// Description: Copies key files from the full directory into the
// reduced directory.
////////////////////////////////////////////////////////////////////
bool IndexImage::
copy_reduced(const Filename &archive_dir) {
Photos::const_iterator pi;
for (pi = _photos.begin(); pi != _photos.end(); ++pi) {
const PhotoInfo &pinfo = (*pi);
int photo_index = pinfo._photo_index;
Photo *photo = _dir->get_photo(photo_index);
// Make sure we have a "reduced" image.
PNMImage reduced_image;
if (!make_reduced_image(photo, reduced_image, false, true)) {
return false;
}
if (photo->_has_movie) {
// Also copy the movie file to the reduced directory, even
// though it's not reduced in any way--but there's no way
// (presently) to reduce a movie file.
Filename movie_filename(_dir->get_dir(), photo->get_movie());
if (movie_filename.exists()) {
movie_filename.set_binary();
Filename reduced_dir(archive_dir, "reduced/" + _dir->get_basename());
if (!copy_file(movie_filename, reduced_dir)) {
return false;
}
}
}
if (photo->_has_sound) {
// Also copy the sound clip to the reduced directory.
Filename sound_filename(_dir->get_dir(), photo->get_sound());
if (sound_filename.exists()) {
sound_filename.set_binary();
Filename reduced_dir(archive_dir, "reduced/" + _dir->get_basename());
if (!copy_file(sound_filename, reduced_dir)) {
return false;
}
}
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: IndexImage::output
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void IndexImage::
output(ostream &out) const {
out << _name;
}
////////////////////////////////////////////////////////////////////
// Function: IndexImage::write
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void IndexImage::
write(ostream &out, int indent_level) const {
indent(out, indent_level)
<< _name << "\n";
Photos::const_iterator pi;
for (pi = _photos.begin(); pi != _photos.end(); ++pi) {
const PhotoInfo &pinfo = (*pi);
indent(out, indent_level + 2)
<< *_dir->get_photo(pinfo._photo_index) << "\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: IndexImage::generate_reduced_html
// Access: Public
// Description: Generates HTML code for rendering the indicated
// reduced-image photo into the given ostream.
////////////////////////////////////////////////////////////////////
bool IndexImage::
generate_reduced_html(ostream &html, Photo *photo, int photo_index, int pi,
const Filename &roll_dir_root) {
Filename full_dir;
if (roll_dir_root.empty()) {
full_dir = Filename("../..", _dir->get_dir());
} else {
compose_href("../..", roll_dir_root, _dir->get_basename());
}
Filename full(full_dir, photo->get_basename());
Filename movie(full_dir, photo->get_movie());
Filename sound(full_dir, photo->get_sound());
Filename reduced_dir("../../reduced", _dir->get_basename());
Filename reduced(reduced_dir, photo->get_basename());
if (!photo->_has_reduced) {
reduced_dir = full_dir;
reduced = full;
}
string up_href = "../" + _dir->get_basename() + ".htm#" + _name;
Filename prev_photo_filename;
Filename next_photo_filename;
if (pi != 0) {
// If this is not the first photo on the index, "back" will take
// us to the previous photo on the same index.
Photo *prev_photo = _dir->get_photo(_photos[pi - 1]._photo_index);
prev_photo_filename = Filename(prev_photo->get_basename());
prev_photo_filename.set_extension("htm");
} else {
// If this is the first photo on the index, "back" will take us to
// the last photo on the previous index. Or even to the last
// photo on the previous roll.
RollDirectory *roll_dir = _dir;
int index = _index - 1;
while (index < 0 && roll_dir->_prev != (RollDirectory *)NULL) {
roll_dir = roll_dir->_prev;
index = roll_dir->get_num_index_images() - 1;
}
if (index >= 0) {
IndexImage *prev_index = roll_dir->get_index_image(index);
nassertr(!prev_index->_photos.empty(), false);
Photo *prev_photo =
roll_dir->get_photo(prev_index->_photos.back()._photo_index);
Filename other_dir("..", roll_dir->get_basename());
prev_photo_filename = Filename(other_dir, prev_photo->get_basename());
prev_photo_filename.set_extension("htm");
}
}
if (pi + 1 < (int)_photos.size()) {
// If this is not the last photo, "next" will take us to the next
// photo on the same index.
Photo *next_photo = _dir->get_photo(_photos[pi + 1]._photo_index);
next_photo_filename = Filename(next_photo->get_basename());
next_photo_filename.set_extension("htm");
} else {
// If this is the last photo on the index, "next" will take us to
// the first photo on the next index. Or even to the first photo
// on the next roll.
RollDirectory *roll_dir = _dir;
int index = _index + 1;
while (index >= roll_dir->get_num_index_images() &&
roll_dir->_next != (RollDirectory *)NULL) {
roll_dir = roll_dir->_next;
index = 0;
}
if (index < roll_dir->get_num_index_images()) {
IndexImage *next_index = roll_dir->get_index_image(index);
nassertr(!next_index->_photos.empty(), false);
Photo *next_photo =
roll_dir->get_photo(next_index->_photos.front()._photo_index);
Filename other_dir("..", roll_dir->get_basename());
next_photo_filename = Filename(other_dir, next_photo->get_basename());
next_photo_filename.set_extension("htm");
}
}
html
<< "<html>\n"
<< "<head>\n"
<< "<title>" << photo->get_name() << " (" << photo_index + 1 << " of "
<< _dir->get_num_photos() << " on " << _dir->get_basename()
<< ")</title>\n"
<< "</head>\n"
<< "<body>\n"
<< "<h1>" << photo->get_name() << " (" << photo_index + 1 << " of "
<< _dir->get_num_photos() << ")</h1>";
generate_nav_buttons(html, prev_photo_filename, next_photo_filename,
up_href);
if (photo->_has_cm) {
// If a comment file for the photo exists, insert its contents
// here, right above the photo.
Filename cm_filename(_dir->get_dir(), photo->get_cm());
if (!RollDirectory::insert_html_comment(html, cm_filename)) {
return false;
}
}
html
<< "<p><a href=\"" << reduced << "\">"
<< "<img src=\"" << reduced << "\" width=" << photo->_reduced_x_size
<< " height=" << photo->_reduced_y_size << " alt=\"" << photo->get_name()
<< "\"></a></p>\n";
if (!omit_full_links && photo->_has_reduced) {
html
<< "<p><a href=\"" << full << "\">View full size image ("
<< photo->_full_x_size << " x " << photo->_full_y_size << ")</a></p>\n";
}
if (photo->_has_movie) {
html << "<p>";
if (!movie_icon.empty()) {
// Show the movie icon if we got one.
Filename movie_icon_href = compose_href("../..", movie_icon);
html << "<img src=\"" << movie_icon_href << "\" alt=\"\">";
}
// Determine the size of the file.
streampos size = 0;
ifstream stream;
Filename movie_filename(_dir->get_dir(), photo->get_movie());
movie_filename.set_binary();
if (movie_filename.open_read(stream)) {
// Seek to the end and get the stream position there.
stream.seekg(0, ios::end);
size = stream.tellg();
}
static const streampos MB = 1024 * 1024;
static const streampos GB = 1024 * 1024 * 1024;
string size_units;
double size_float = size;
if (size > GB) {
size_units = "GB";
size_float = (double)size / (double)GB;
} else if (size > MB) {
size_units = "MB";
size_float = (double)size / (double)MB;
}
if (size_units.empty()) {
html
<< "<a href=\"" << movie << "\">Play movie</a></p>\n";
} else {
char buffer[128];
sprintf(buffer, "%.1f", size_float);
html
<< "<a href=\"" << movie << "\">Play movie ("
<< buffer << " " << size_units << ")</a></p>\n";
}
}
if (photo->_has_sound) {
html << "<p>";
if (!sound_icon.empty()) {
// Show the sound icon if we got one.
Filename sound_icon_href = compose_href("../..", sound_icon);
html << "<img src=\"" << sound_icon_href << "\" alt=\"\">";
}
// Determine the size of the file.
streampos size = 0;
ifstream stream;
Filename sound_filename(_dir->get_dir(), photo->get_sound());
sound_filename.set_binary();
if (sound_filename.open_read(stream)) {
// Seek to the end and get the stream position there.
stream.seekg(0, ios::end);
size = stream.tellg();
}
static const streampos MB = 1024 * 1024;
static const streampos GB = 1024 * 1024 * 1024;
string size_units;
double size_float = size;
if (size > GB) {
size_units = "GB";
size_float = (double)size / (double)GB;
} else if (size > MB) {
size_units = "MB";
size_float = (double)size / (double)MB;
}
if (size_units.empty()) {
html
<< "<a href=\"" << sound << "\">Play sound clip</a></p>\n";
} else {
char buffer[128];
sprintf(buffer, "%.1f", size_float);
html
<< "<a href=\"" << sound << "\">Play sound clip ("
<< buffer << " " << size_units << ")</a></p>\n";
}
}
generate_nav_buttons(html, prev_photo_filename, next_photo_filename,
up_href);
html
<< "</body>\n"
<< "</html>\n";
return true;
}
////////////////////////////////////////////////////////////////////
// Function: IndexImage::generate_nav_buttons
// Access: Private
// Description: Outputs the HTML code to generate the next, prev,
// up buttons when viewing each reduced image.
////////////////////////////////////////////////////////////////////
void IndexImage::
generate_nav_buttons(ostream &html, const Filename &prev_photo_filename,
const Filename &next_photo_filename,
const string &up_href) {
html << "<p>\n";
bool first_icons = false;
if (!prev_icon.empty() && !next_icon.empty()) {
first_icons = true;
// Use icons to go forward and back.
Filename prev_icon_href = compose_href("../..", prev_icon);
if (prev_photo_filename.empty()) {
html << "<img src=\"" << prev_icon_href << "\" alt=\"No previous photo\">\n";
} else {
html << "<a href=\"" << prev_photo_filename
<< "\"><img src=\"" << prev_icon_href << "\" alt=\"previous\"></a>\n";
}
Filename next_icon_href = compose_href("../..", next_icon);
if (next_photo_filename.empty()) {
html << "<img src=\"" << next_icon_href << "\" alt=\"No next photo\">\n";
} else {
html << "<a href=\"" << next_photo_filename
<< "\"><img src=\"" << next_icon_href << "\" alt=\"next\"></a>\n";
}
} else {
// No prev/next icons; use text to go forward and back.
if (prev_photo_filename.empty()) {
html << "(This is the first photo.)\n";
} else {
html << "<a href=\"" << prev_photo_filename
<< "\">Back to previous photo</a>\n";
}
if (next_photo_filename.empty()) {
html << "<br>(This is the last photo.)\n";
} else {
html << "<br><a href=\"" << next_photo_filename
<< "\">On to next photo</a>\n";
}
}
if (!up_href.empty()) {
if (!up_icon.empty()) {
// Use an icon to go up.
if (!first_icons) {
html << "<br>";
} else {
html << "&nbsp;&nbsp;&nbsp;";
}
Filename up_icon_href = compose_href("../..", up_icon);
html << "<a href=\"" << up_href
<< "\"><img src=\"" << up_icon_href << "\" alt=\"return to index\"></a>\n";
} else {
// No up icon; use text to go up.
html << "<br><a href=\"" << up_href
<< "\">Return to index</a>\n";
}
}
html << "</p>\n";
}
////////////////////////////////////////////////////////////////////
// Function: IndexImage::compute_reduction
// Access: Private, Static
// Description: Computes the amount by which the source image must be
// scaled to fit within the indicated box, and clears
// the dest_image to the computed size.
////////////////////////////////////////////////////////////////////
void IndexImage::
compute_reduction(const PNMImageHeader &source_image, PNMImage &dest_image,
int x_size, int y_size) {
double x_scale = (double)x_size / (double)source_image.get_x_size();
double y_scale = (double)y_size / (double)source_image.get_y_size();
double scale = min(x_scale, y_scale);
// Don't ever enlarge an image to fit the rectangle; if the image is
// smaller than the rectangle, just leave it small.
scale = min(scale, 1.0);
int new_x_size = (int)(source_image.get_x_size() * scale + 0.5);
int new_y_size = (int)(source_image.get_y_size() * scale + 0.5);
dest_image.clear(new_x_size, new_y_size,
source_image.get_num_channels(),
source_image.get_maxval());
}
////////////////////////////////////////////////////////////////////
// Function: IndexImage::draw_box
// Access: Private, Static
// Description: Called in dummy mode to draw a little box in black
// around the border of the empty thumbnail image.
////////////////////////////////////////////////////////////////////
void IndexImage::
draw_box(PNMImage &image) {
// First, fill it in white.
image.fill(1, 1, 1);
if (!draw_frames) {
// Now make the border pixel black. We only need to do this if we
// aren't drawing frames, since the frames will reveal the shape
// of the image too.
int x_size = image.get_x_size();
int y_size = image.get_y_size();
for (int xi = 0; xi < x_size; xi++) {
image.set_xel(xi, 0, 0, 0, 0);
image.set_xel(xi, y_size - 1, 0, 0, 0);
}
for (int yi = 1; yi < y_size - 1; yi++) {
image.set_xel(0, yi, 0, 0, 0);
image.set_xel(x_size - 1, yi, 0, 0, 0);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: IndexImage::draw_frame
// Access: Private, Static
// Description: Called in draw_frames mode to draw a slide mount in
// gray on the index image before drawing the thumbnail
// image in the center.
////////////////////////////////////////////////////////////////////
void IndexImage::
draw_frame(PNMImage &image,
int frame_left, int frame_top, int frame_width, int frame_height,
int hole_left, int hole_top, int hole_width, int hole_height) {
// Gray levels.
static const RGBColord mid(0.5, 0.5, 0.5);
static const RGBColord light(0.7, 0.7, 0.7);
static const RGBColord lighter(0.9, 0.9, 0.9);
static const RGBColord dark(0.3, 0.3, 0.3);
static const RGBColord darker(0.1, 0.1, 0.1);
// First, fill in the whole rectangle in gray.
int xi, yi;
for (yi = 0; yi < frame_height; yi++) {
for (xi = 0; xi < frame_width; xi++) {
image.set_xel(xi + frame_left, yi + frame_top, mid);
}
}
// Now draw the bevel.
for (xi = 0; xi < frame_outer_bevel; xi++) {
for (yi = xi; yi < frame_height - xi; yi++) {
// Left edge.
image.set_xel(xi + frame_left, yi + frame_top, light);
// Right edge.
image.set_xel(frame_width - 1 - xi + frame_left, yi + frame_top, dark);
}
}
for (yi = 0; yi < frame_outer_bevel; yi++) {
for (xi = yi; xi < frame_width - yi; xi++) {
// Top edge.
image.set_xel(xi + frame_left, yi + frame_top, lighter);
// Bottom edge.
image.set_xel(xi + frame_left, frame_height - 1 - yi + frame_top, darker);
}
}
// Interior bevel.
for (xi = -1; xi >= -frame_inner_bevel; xi--) {
for (yi = xi; yi < hole_height - xi; yi++) {
// Left edge.
image.set_xel(xi + hole_left, yi + hole_top, dark);
// Right edge.
image.set_xel(hole_width - 1 - xi + hole_left, yi + hole_top, light);
}
}
for (yi = -1; yi >= -frame_inner_bevel; yi--) {
for (xi = yi; xi < hole_width - yi; xi++) {
// Top edge.
image.set_xel(xi + hole_left, yi + hole_top, darker);
// Bottom edge.
image.set_xel(xi + hole_left, hole_height - 1 - yi + hole_top, lighter);
}
}
// We don't have to cut out the hole, since the thumbnail image will
// do that when it is placed.
}

View File

@ -1,96 +0,0 @@
// Filename: indexImage.h
// Created by: drose (03Apr02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef INDEXIMAGE_H
#define INDEXIMAGE_H
#include "pandatoolbase.h"
#include "filename.h"
#include "pvector.h"
class RollDirectory;
class Photo;
class PNMTextMaker;
class PNMImage;
class PNMImageHeader;
////////////////////////////////////////////////////////////////////
// Class : IndexImage
// Description : An aggregate image containing several thumbnails, one
// for each of several photos. A roll directory will
// collect its photos into one or more IndexImages.
////////////////////////////////////////////////////////////////////
class IndexImage {
public:
IndexImage(RollDirectory *dir, int index);
~IndexImage();
bool add_photo(int index);
bool generate_images(const Filename &archive_dir, PNMTextMaker *text_maker);
bool make_reduced_image(Photo *photo, PNMImage &reduced_image,
bool generate_index_image, bool force_reduced);
bool generate_html(ostream &root_html, const Filename &archive_dir,
const Filename &roll_dir_root);
bool copy_reduced(const Filename &archive_dir);
void output(ostream &out) const;
void write(ostream &out, int indent_level) const;
private:
bool generate_reduced_html(ostream &html, Photo *photo, int photo_index,
int pi, const Filename &roll_dir_root);
void generate_nav_buttons(ostream &html, const Filename &prev_photo_filename,
const Filename &next_photo_filename,
const string &up_href);
static void compute_reduction(const PNMImageHeader &source_image,
PNMImage &dest_image,
int x_size, int y_size);
static void draw_box(PNMImage &image);
static void draw_frame(PNMImage &image,
int frame_left, int frame_top,
int frame_width, int frame_height,
int hole_left, int hole_top,
int hole_width, int hole_height);
private:
RollDirectory *_dir;
int _index;
string _name;
class PhotoInfo {
public:
int _photo_index;
int _x_place;
int _y_place;
};
typedef pvector<PhotoInfo> Photos;
Photos _photos;
int _index_x_size;
int _index_y_size;
string _index_basename;
};
INLINE ostream &operator << (ostream &out, const IndexImage &d) {
d.output(out);
return out;
}
#endif

View File

@ -1,296 +0,0 @@
// Filename: indexParameters.cxx
// Created by: drose (04Apr02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "indexParameters.h"
// User parameters
int max_index_size_array[2] = { 700, 700 };
int thumb_size_array[2] = { 150, 150 };
int thumb_caption_height = 12;
int caption_font_size = 12;
int thumb_space_array[2] = { 12, 12 };
double frame_reduction_factor = 0.75;
int frame_outer_bevel = 2;
int frame_inner_bevel = 1;
int reduced_size_array[2] = { 800, 700 };
Filename archive_dir;
Filename prev_icon;
Filename next_icon;
Filename up_icon;
Filename movie_icon;
Filename sound_icon;
////////////////////////////////////////////////////////////////////
// Function: get_movie_icon
// Description: Reads the movie icon filename and returns it as an
// image, if possible. Returns a valid image if
// successful, an invalid one otherwise.
////////////////////////////////////////////////////////////////////
const PNMImage &
get_movie_icon() {
static PNMImage movie_icon_image;
static bool got_image = false;
if (!got_image) {
if (!movie_icon.empty()) {
Filename icon_filename(archive_dir, movie_icon);
nout << "Reading " << icon_filename << "\n";
movie_icon_image.read(icon_filename);
}
got_image = true;
}
return movie_icon_image;
}
////////////////////////////////////////////////////////////////////
// Function: get_sound_icon
// Description: Reads the sound icon filename and returns it as an
// image, if possible. Returns a valid image if
// successful, an invalid one otherwise.
////////////////////////////////////////////////////////////////////
const PNMImage &
get_sound_icon() {
static PNMImage sound_icon_image;
static bool got_image = false;
if (!got_image) {
if (!sound_icon.empty()) {
Filename icon_filename(archive_dir, sound_icon);
nout << "Reading " << icon_filename << "\n";
sound_icon_image.read(icon_filename);
}
got_image = true;
}
return sound_icon_image;
}
bool force_regenerate = false;
bool format_rose = false;
bool sort_date = false;
bool dummy_mode = false;
bool draw_frames = false;
bool omit_roll_headers = false;
DSearchPath cm_search;
bool omit_full_links = false;
bool omit_complete = false;
bool caption_frame_numbers = false;
// Computed parameters
int thumb_count_x;
int thumb_count_y;
int max_thumbs;
int actual_index_width;
int thumb_interior_width;
int thumb_interior_height;
////////////////////////////////////////////////////////////////////
// Function: finalize_parameters
// Description: This is called after all user parameters have been
// changed, to do whatever computations are required for
// the other parameters that are based on the user
// parameters.
////////////////////////////////////////////////////////////////////
void
finalize_parameters() {
thumb_count_x =
(max_index_width - thumb_x_space) / (thumb_width + thumb_x_space);
thumb_count_y =
(max_index_height - thumb_y_space) / (thumb_height + thumb_caption_height + thumb_y_space);
max_thumbs = thumb_count_x * thumb_count_y;
actual_index_width = thumb_x_space + thumb_count_x * (thumb_width + thumb_x_space);
if (draw_frames) {
thumb_interior_width = (int)(thumb_width * frame_reduction_factor + 0.5);
thumb_interior_height = (int)(thumb_height * frame_reduction_factor + 0.5);
} else {
thumb_interior_width = thumb_width;
thumb_interior_height = thumb_height;
}
}
////////////////////////////////////////////////////////////////////
// Function: compose_href
// Description: Combines a user-supplied prefix with a relative
// directory to generate the appropriate href to the
// file.
//
// rel_dir is the relative path to archive_dir.
// user_prefix is the string the user indicated as the
// relative or absolute path to the file's parent
// directory from archive_dir. basename is the name
// of the file, or empty if the filename is part of
// user_prefix.
////////////////////////////////////////////////////////////////////
Filename
compose_href(const Filename &rel_dir, const Filename &user_prefix,
const Filename &basename) {
Filename result;
if (user_prefix.empty()) {
result = rel_dir;
} else {
// Check to see if the user prefix begins with a URL designator,
// like http:// or ftp://.
size_t ui = 0;
while (ui < user_prefix.length() && isalpha(user_prefix[ui])) {
ui++;
}
bool is_url = (user_prefix.get_fullpath().substr(ui, 3) == "://");
if (!is_url && user_prefix.is_local()) {
Filename rel_user_dir(rel_dir, user_prefix);
result = rel_user_dir;
result.standardize();
} else {
result = user_prefix;
}
}
if (basename.empty()) {
return result;
} else {
return Filename(result, basename);
}
}
////////////////////////////////////////////////////////////////////
// Function: escape_html
// Description: Returns the input string with all invalid characters
// for HTML code replaced by their HTML equivalents.
////////////////////////////////////////////////////////////////////
string
escape_html(const string &input) {
static const struct {
const char *name;
int code;
} tokens[] = {
{ "amp", '&' }, { "lt", '<' }, { "gt", '>' }, { "quot", '"' },
{ "nbsp", 160 },
{ "iexcl", 161 }, { "cent", 162 }, { "pound", 163 }, { "curren", 164 },
{ "yen", 165 }, { "brvbar", 166 }, { "brkbar", 166 }, { "sect", 167 },
{ "uml", 168 }, { "die", 168 }, { "copy", 169 }, { "ordf", 170 },
{ "laquo", 171 }, { "not", 172 }, { "shy", 173 }, { "reg", 174 },
{ "macr", 175 }, { "hibar", 175 }, { "deg", 176 }, { "plusmn", 177 },
{ "sup2", 178 }, { "sup3", 179 }, { "acute", 180 }, { "micro", 181 },
{ "para", 182 }, { "middot", 183 }, { "cedil", 184 }, { "sup1", 185 },
{ "ordm", 186 }, { "raquo", 187 }, { "frac14", 188 }, { "frac12", 189 },
{ "frac34", 190 }, { "iquest", 191 }, { "Agrave", 192 }, { "Aacute", 193 },
{ "Acirc", 194 }, { "Atilde", 195 }, { "Auml", 196 }, { "Aring", 197 },
{ "AElig", 198 }, { "Ccedil", 199 }, { "Egrave", 200 }, { "Eacute", 201 },
{ "Ecirc", 202 }, { "Euml", 203 }, { "Igrave", 204 }, { "Iacute", 205 },
{ "Icirc", 206 }, { "Iuml", 207 }, { "ETH", 208 }, { "Dstrok", 208 },
{ "Ntilde", 209 }, { "Ograve", 210 }, { "Oacute", 211 }, { "Ocirc", 212 },
{ "Otilde", 213 }, { "Ouml", 214 }, { "times", 215 }, { "Oslash", 216 },
{ "Ugrave", 217 }, { "Uacute", 218 }, { "Ucirc", 219 }, { "Uuml", 220 },
{ "Yacute", 221 }, { "THORN", 222 }, { "szlig", 223 }, { "agrave", 224 },
{ "aacute", 225 }, { "acirc", 226 }, { "atilde", 227 }, { "auml", 228 },
{ "aring", 229 }, { "aelig", 230 }, { "ccedil", 231 }, { "egrave", 232 },
{ "eacute", 233 }, { "ecirc", 234 }, { "euml", 235 }, { "igrave", 236 },
{ "iacute", 237 }, { "icirc", 238 }, { "iuml", 239 }, { "eth", 240 },
{ "ntilde", 241 }, { "ograve", 242 }, { "oacute", 243 }, { "ocirc", 244 },
{ "otilde", 245 }, { "ouml", 246 }, { "divide", 247 }, { "oslash", 248 },
{ "ugrave", 249 }, { "uacute", 250 }, { "ucirc", 251 }, { "uuml", 252 },
{ "yacute", 253 }, { "thorn", 254 }, { "yuml", 255 },
{ NULL, 0 },
};
string result;
for (string::const_iterator ii = input.begin();
ii != input.end();
++ii) {
int code = (unsigned char)(*ii);
bool found_match = false;
for (int i = 0; !found_match && tokens[i].name != NULL; i++) {
if (code == tokens[i].code) {
result += '&';
result += tokens[i].name;
result += ';';
found_match = true;
}
}
if (!found_match) {
result += (*ii);
}
}
return result;
}
////////////////////////////////////////////////////////////////////
// Function: copy_file
// Description: Copies a file into the named directory, if it does
// not already exist there. Returns true if
// successful, false otherwise.
////////////////////////////////////////////////////////////////////
bool
copy_file(const Filename &source_file, const Filename &dest_dir) {
Filename dest_file = source_file;
dest_file.set_dirname(dest_dir);
if (dest_file.exists()) {
return true;
}
if (!source_file.exists()) {
return false;
}
#if defined(HAVE_UNISTD_H) && !defined(WIN32)
// Try to make a hard link.
string os_source_file = source_file.to_os_specific();
string os_dest_file = dest_file.to_os_specific();
if (link(os_source_file.c_str(), os_dest_file.c_str()) == 0) {
cerr << "Linked " << source_file << " to " << dest_file << "\n";
return true;
}
#endif
ifstream in;
if (!source_file.open_read(in)) {
cerr << "Unable to read " << source_file << "\n";
return false;
}
ofstream out;
if (!dest_file.open_write(out)) {
cerr << "Unable to write " << dest_file << "\n";
return false;
}
cerr << "Copying " << source_file << " to " << dest_file << "\n";
int c = in.get();
while (in && !in.eof()) {
out.put(c);
c = in.get();
}
return in.eof();
}

View File

@ -1,154 +0,0 @@
// Filename: indexParameters.h
// Created by: drose (04Apr02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef INDEXPARAMETERS_H
#define INDEXPARAMETERS_H
#include "pandatoolbase.h"
#include "filename.h"
#include "dSearchPath.h"
#include "pnmImage.h"
// Some of these constants may be modified by command-line parameters
// from the user.
// The maximum size of the index image. It will shrink vertically to
// fit the images it contains, and it will shrink horizontally to fit
// a complete row of images (even if it does not contain a complete
// row). It will never be larger than this.
extern int max_index_size_array[2];
#define max_index_width (max_index_size_array[0])
#define max_index_height (max_index_size_array[1])
// The size of the individual thumbnail images, including the frames
// (if present). Thumbnail images are scaled to fit within this box.
extern int thumb_size_array[2];
#define thumb_width (thumb_size_array[0])
#define thumb_height (thumb_size_array[1])
// The total number of pixels reserved for the caption under each
// thumbnail image. This is the caption_font_size plus whatever
// spacing should be included between the caption and the image.
extern int thumb_caption_height;
// The size in pixels of the caption font. This depends on the point
// size of the font as reported by FreeType, so the actual height of
// the letters might be slightly lower or higher than this, depending
// on the font.
extern int caption_font_size;
// The amount of space, in pixels, between each two neighboring
// thumbnail images, and around the overall index image.
extern int thumb_space_array[2];
#define thumb_x_space (thumb_space_array[0])
#define thumb_y_space (thumb_space_array[1])
// The ratio by which the thumbnail images are reduced further when
// frames are drawn, to allow room for a frame that resembles a slide
// mount.
extern double frame_reduction_factor;
// The number of pixels of thickness to draw for the frames' outer
// bevels and inner bevels, respectively.
extern int frame_outer_bevel;
extern int frame_inner_bevel;
// The size of the reduced images on the individual image pages. The
// source image will be scaled to fit within this rectangle.
extern int reduced_size_array[2];
#define reduced_width (reduced_size_array[0])
#define reduced_height (reduced_size_array[1])
// The directory at the root of the output hierarchy (or as specified
// by -a on the command line).
extern Filename archive_dir;
// The filenames (or URLS) to the icon images for navigating the
// individual image pages.
extern Filename prev_icon;
extern Filename next_icon;
extern Filename up_icon;
extern Filename movie_icon;
extern Filename sound_icon;
const PNMImage &get_movie_icon();
const PNMImage &get_sound_icon();
// True to regenerate every image, whether it appears to need it or
// not.
extern bool force_regenerate;
// True to use the Rose formatting convention for roll directory names.
extern bool format_rose;
// True to sort roll directory names by date. Useful only with -r.
extern bool sort_date;
// True to place dummy thumbnails instead of loading actual images.
extern bool dummy_mode;
// True to draw frames (slide mounts) around each thumbnail image.
extern bool draw_frames;
// True to avoid introducing each roll directory on the index page
// with its own little header. This also ignored the roll.cm file if
// it exists.
extern bool omit_roll_headers;
extern DSearchPath cm_search;
// True to omit links to the full-size source images.
extern bool omit_full_links;
// True to omit complete.htm
extern bool omit_complete;
// True to caption photos with just a frame number instead of the
// whole image basename. This only works if the photo image filenames
// consist of the roll directory name concatenated with a frame number.
extern bool caption_frame_numbers;
void finalize_parameters();
// The following parameters are all computed based on the above.
// The number of thumbnail images that fit across an index image,
// horizontally and vertically.
extern int thumb_count_x;
extern int thumb_count_y;
// The total number of thumbnail images within each index image.
extern int max_thumbs;
// The number of pixels wide each index image will actually be, based
// on thumb_count_x.
extern int actual_index_width;
// The actual size of the rectangle each thumbnail image must be
// scaled into, accounting for the presence of a frame.
extern int thumb_interior_width;
extern int thumb_interior_height;
Filename compose_href(const Filename &rel_dir, const Filename &user_prefix,
const Filename &basename = Filename());
string escape_html(const string &input);
bool copy_file(const Filename &source_file, const Filename &dest_dir);
#endif

View File

@ -1,738 +0,0 @@
// Filename: indexify.cxx
// Created by: drose (03Apr02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "indexify.h"
#include "rollDirectory.h"
#include "pnotify.h"
#include "pnmTextMaker.h"
#include "default_font.h"
#include "default_index_icons.h"
#include "indexParameters.h"
#include "string_utils.h"
#include <algorithm>
////////////////////////////////////////////////////////////////////
// Function: Indexify::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
Indexify::
Indexify() {
clear_runlines();
add_runline("[opts] roll1-dir roll2-dir [roll3-dir ...]");
add_runline("[opts] full/*");
set_program_description
("This program reads a collection of directories containing photo "
"archives (typically JPEG files), and will generate a number of "
"thumbnail images and a series of HTML pages to browse them. It is "
"especially useful in preparation for burning the photo archives to "
"CD.\n\n"
"A number of directories is named on the command line; each "
"directory must contain a number of image files, and all directories "
"should be within the same parent directory. Each directory is "
"considered a \"roll\", which may or may not correspond to a physical "
"roll of film, and the photos within each directory are grouped "
"correspondingly on the generated HTML pages. One common special case "
"is in which all the roll directories are found in the subdirectory "
"named \"full\" (e.g., the second example above) or \"reduced\". This "
"keeps the root directory nice and clean.\n\n"
"If a file exists by the same name as an image file but with the "
"extension \"cm\", that file is taken to be a HTML comment about that "
"particular image and is inserted the HTML page for that image. "
"Similarly, if there is a file within a roll directory with the same "
"name as the directory itself (but with the extension \"cm\"), that file "
"is inserted into the front page to introduce that particular roll. "
"Finally, a file with the name of the directory, but with the extension "
"\"ds\" may contain a brief one-line description of the directory, for "
"the toplevel index page.\n\n"
"Normally, all image files with the specified extension (normally "
"\"jpg\") within a roll directory are included in the index, and sorted "
"into alphabetical (or numerical) order. If you wish to specify a "
"different order, or use only a subset of the images in a directory, "
"create a file in the roll directory with the same name as the "
"directory itself, and the extension \"ls\". This file should "
"simply list the filenames (with or without extension) within the "
"roll directory in the order they should be listed. If the ls "
"file exists but is empty, it indicates that the files should be "
"listed in reverse order, as from a camera that loads its film "
"upside-down.");
add_option
("t", "title", 0,
"Specifies the title to give to the front HTML page.",
&Indexify::dispatch_string, NULL, &_front_title);
add_option
("a", "archive-dir", 0,
"Write the generated files to the indicated directory, instead of "
"the directory above roll1-dir.",
&Indexify::dispatch_filename, NULL, &archive_dir);
add_option
("r", "relative-dir", 0,
"When -a is specified to place the generated html files in a directory "
"other than the default, you may need "
"to specify how the html files will address the roll directories. This "
"parameter specifies the relative path to the directory above the roll "
"directories, from the directory named by -a.",
&Indexify::dispatch_filename, NULL, &_roll_dir_root);
add_option
("f", "", 0,
"Forces the regeneration of all reduced and thumbnail images, even if "
"image files already exist that seem to be newer than the source "
"image files.",
&Indexify::dispatch_none, &force_regenerate);
add_option
("r", "", 0,
"Specifies that roll directory names are encoded using the Rose "
"convention of six digits: mmyyss, where mm and yy are the month and "
"year, and ss is a sequence number of the roll within the month. This "
"name will be reformatted to m-yy/s for output.",
&Indexify::dispatch_none, &format_rose);
add_option
("s", "", 0,
"When used in conjunction with -r, requests sorting of the roll "
"directory names by date.",
&Indexify::dispatch_none, &sort_date);
add_option
("d", "", 0,
"Run in \"dummy\" mode; don't load any images, but instead just "
"draw an empty box indicating where the thumbnails will be.",
&Indexify::dispatch_none, &dummy_mode);
add_option
("slide", "", 0,
"Draw a frame, like a slide mount, around each thumbnail image.",
&Indexify::dispatch_none, &draw_frames);
add_option
("pe", "extension", 0,
"Specifies the filename extension (without a leading dot) to identify "
"photo files within the roll directories. This is normally jpg.",
&Indexify::dispatch_string, NULL, &_photo_extension);
add_option
("me", "extension", 0,
"Specifies the filename extension (without a leading dot) to identify "
"movie files within the roll directories. This is normally mov. If "
"a file exists with the same name as a given photo but with this "
"extension, it is taken to be a movie associated with the photo, and "
"a link will be generated to play the movie.",
&Indexify::dispatch_string, NULL, &_movie_extension);
add_option
("se", "extension", 0,
"Specifies the filename extension (without a leading dot) to identify "
"sound files within the roll directories. This is normally mp3. If "
"a file exists with the same name as a given photo but with this "
"extension, it is taken to be a sound clip associated with the photo, "
"and a link will be generated to play the clip.",
&Indexify::dispatch_string, NULL, &_sound_extension);
add_option
("i", "", 0,
"Indicates that default navigation icon images should be generated "
"into a directory called \"icons\" which will be created within the "
"directory named by -a. This is meaningful only if -iprev, -inext, "
"-iup, -imovie, and -isound are not explicitly specified.",
&Indexify::dispatch_none, &_generate_icons);
add_option
("omit-rh", "", 0,
"Omits roll headers introducing each roll directory, including any "
"headers defined in roll.cm files.",
&Indexify::dispatch_none, &omit_roll_headers);
add_option
("cmdir", "director", 0,
"Searches in the named directory for .cm files before searching within "
"the source archive. This option may be repeated.",
&Indexify::dispatch_search_path, NULL, &cm_search);
add_option
("omit-full", "", 0,
"Omits links to the full-size images.",
&Indexify::dispatch_none, &omit_full_links);
add_option
("omit-complete", "", 0,
"Omits the complete.htm index file that lists all thumbnails at once.",
&Indexify::dispatch_none, &omit_complete);
add_option
("caption", "size[,spacing]", 0,
"Specifies the font size in pixels of the thumbnail captions. If the "
"optional spacing parameter is included, it is the number of pixels "
"below each thumbnail that the caption should be placed. Specify "
"-caption 0 to disable thumbnail captions.",
&Indexify::dispatch_caption, NULL);
add_option
("fnum", "", 0,
"Writes the frame number of each thumbnail image into the caption "
"on the index page, instead of the image filename. This only works "
"if the photo image filenames consist of the roll directory name "
"concatenated with a frame number.",
&Indexify::dispatch_none, &caption_frame_numbers);
add_option
("font", "fontname", 0,
"Specifies the filename of the font to use to generate the thumbnail "
"captions.",
&Indexify::dispatch_filename, NULL, &_font_filename);
add_option
("fontaa", "factor", 0,
"Specifies a scale factor to apply to the fonts used for captioning "
"when generating text for the purpose of antialiasing the fonts a "
"little better than FreeType can do by itself. The letters are "
"generated large and then scaled to their proper size. Normally this "
"should be a number in the range 3 to 4 for best effect.",
&Indexify::dispatch_double, NULL, &_font_aa_factor);
add_option
("thumb", "x,y", 0,
"Specifies the size in pixels of the thumbnail images.",
&Indexify::dispatch_int_pair, NULL, &thumb_width);
add_option
("reduced", "x,y", 0,
"Specifies the size in pixels of reduced images (images presented after "
"the first click on a thumbnail).",
&Indexify::dispatch_int_pair, NULL, &reduced_width);
add_option
("space", "x,y", 0,
"Specifies the x,y spacing between thumbnail images, in pixels.",
&Indexify::dispatch_int_pair, NULL, &thumb_x_space);
add_option
("index", "x,y", 0,
"Specifies the size in pixels of the index images (the images that "
"contain an index of thumbnails).",
&Indexify::dispatch_int_pair, NULL, &max_index_width);
add_option
("iprev", "filename", 0,
"Specifies the relative pathname from the archive directory (or "
"absolute pathname) to the \"previous\" icon.",
&Indexify::dispatch_filename, NULL, &prev_icon);
add_option
("inext", "filename", 0,
"Specifies the relative pathname from the archive directory (or "
"absolute pathname) to the \"next\" icon.",
&Indexify::dispatch_filename, NULL, &next_icon);
add_option
("iup", "filename", 0,
"Specifies the relative pathname from the archive directory (or "
"absolute pathname) to the \"up\" icon.",
&Indexify::dispatch_filename, NULL, &up_icon);
add_option
("imovie", "filename", 0,
"Specifies the relative pathname from the archive directory (or "
"absolute pathname) to the \"movie\" icon. This is used only if "
"there are one or more movie files found in the directory.",
&Indexify::dispatch_filename, NULL, &movie_icon);
add_option
("isound", "filename", 0,
"Specifies the relative pathname from the archive directory (or "
"absolute pathname) to the \"sound\" icon. This is used only if "
"there are one or more sound files found in the directory.",
&Indexify::dispatch_filename, NULL, &sound_icon);
add_option
("copyreduced", "", 0,
"Instead of generating index files, copy key files (such as "
"*.cm, *.ds) from the full image directory into the reduced "
"image directory, so that the full image directory may be removed "
"for generating a reduced-size archive.",
&Indexify::dispatch_none, &_copy_reduced);
_photo_extension = "jpg";
_movie_extension = "mov";
_sound_extension = "mp3";
_text_maker = (PNMTextMaker *)NULL;
_font_aa_factor = 4.0;
}
////////////////////////////////////////////////////////////////////
// Function: Indexify::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
Indexify::
~Indexify() {
RollDirs::iterator di;
for (di = _roll_dirs.begin(); di != _roll_dirs.end(); ++di) {
RollDirectory *roll_dir = (*di);
delete roll_dir;
}
if (_text_maker != (PNMTextMaker *)NULL) {
delete _text_maker;
}
}
////////////////////////////////////////////////////////////////////
// Function: Indexify::handle_args
// Access: Protected, Virtual
// Description: Does something with the additional arguments on the
// command line (after all the -options have been
// parsed). Returns true if the arguments are good,
// false otherwise.
////////////////////////////////////////////////////////////////////
bool Indexify::
handle_args(ProgramBase::Args &args) {
if (args.empty()) {
nout << "You must specify the roll directories containing archive photos on the command line.\n";
return false;
}
Args::const_iterator ai;
for (ai = args.begin(); ai != args.end(); ++ai) {
Filename filename = Filename::from_os_specific(*ai);
filename.standardize();
if (filename.is_directory()) {
string basename = filename.get_basename();
if (basename == "icons" || basename == "html" ||
basename == "reduced" || basename == "thumbs") {
nout << "Ignoring " << filename << "; indexify-generated directory.\n";
} else {
RollDirectory *roll_dir = new RollDirectory(filename);
_roll_dirs.push_back(roll_dir);
}
} else if (filename.exists()) {
nout << "Ignoring " << filename << "; not a directory.\n";
} else {
nout << filename << " does not exist.\n";
return false;
}
}
return true;
}
class SortRollDirs {
public:
bool operator () (const RollDirectory *a, const RollDirectory *b) const {
return a->sort_date_before(*b);
}
};
////////////////////////////////////////////////////////////////////
// Function: Indexify::post_command_line
// Access: Protected, Virtual
// Description: This is called after the command line has been
// completely processed, and it gives the program a
// chance to do some last-minute processing and
// validation of the options and arguments. It should
// return true if everything is fine, false if there is
// an error.
////////////////////////////////////////////////////////////////////
bool Indexify::
post_command_line() {
if (_roll_dirs.empty()) {
nout << "No roll directories.\n";
return false;
}
if (archive_dir.empty()) {
// Choose a default archive directory, above the first roll directory.
archive_dir = _roll_dirs.front()->get_dir().get_dirname();
string parent_dirname = archive_dir.get_basename();
if (parent_dirname == "full" || parent_dirname == "reduced") {
// As a special case, if the subdirectory name is "full" or
// "reduced", use the directory above that.
archive_dir = archive_dir.get_dirname();
}
if (archive_dir.empty()) {
archive_dir = ".";
}
}
archive_dir.standardize();
if (!_roll_dir_root.empty()) {
_roll_dir_root.standardize();
}
// Sort the roll directories, if specified.
if (format_rose && sort_date) {
sort(_roll_dirs.begin(), _roll_dirs.end(), SortRollDirs());
}
// Update the next/prev pointers in each roll directory so we can
// browse from one to the other.
RollDirectory *prev_roll_dir = (RollDirectory *)NULL;
RollDirs::iterator di;
for (di = _roll_dirs.begin(); di != _roll_dirs.end(); ++di) {
RollDirectory *roll_dir = (*di);
if (prev_roll_dir != (RollDirectory *)NULL) {
roll_dir->_prev = prev_roll_dir;
prev_roll_dir->_next = roll_dir;
}
prev_roll_dir = roll_dir;
}
if (_front_title.empty()) {
// Supply a default title.
if (_roll_dirs.size() == 1) {
_front_title = _roll_dirs.front()->get_name();
} else {
_front_title = _roll_dirs.front()->get_name() + " through " + _roll_dirs.back()->get_name();
}
}
if (caption_font_size != 0) {
if (!_font_filename.empty()) {
_text_maker = new PNMTextMaker(_font_filename, 0);
if (!_text_maker->is_valid()) {
delete _text_maker;
_text_maker = (PNMTextMaker *)NULL;
}
}
if (_text_maker == (PNMTextMaker *)NULL) {
_text_maker = new PNMTextMaker((const char *)default_font,
default_font_size, 0);
if (!_text_maker->is_valid()) {
nout << "Unable to open default font.\n";
delete _text_maker;
_text_maker = (PNMTextMaker *)NULL;
}
}
if (_text_maker != (PNMTextMaker *)NULL) {
_text_maker->set_scale_factor(_font_aa_factor);
_text_maker->set_pixel_size(caption_font_size);
_text_maker->set_align(PNMTextMaker::A_center);
}
}
if (_generate_icons) {
if (prev_icon.empty()) {
prev_icon = Filename("icons", default_left_icon_filename);
Filename icon_filename(archive_dir, prev_icon);
if (force_regenerate || !icon_filename.exists()) {
nout << "Generating " << icon_filename << "\n";
icon_filename.make_dir();
icon_filename.set_binary();
ofstream output;
if (!icon_filename.open_write(output)) {
nout << "Unable to write to " << icon_filename << "\n";
exit(1);
}
output.write((const char *)default_left_icon, default_left_icon_len);
}
}
if (next_icon.empty()) {
next_icon = Filename("icons", default_right_icon_filename);
Filename icon_filename(archive_dir, next_icon);
if (force_regenerate || !icon_filename.exists()) {
nout << "Generating " << icon_filename << "\n";
icon_filename.make_dir();
icon_filename.set_binary();
ofstream output;
if (!icon_filename.open_write(output)) {
nout << "Unable to write to " << icon_filename << "\n";
exit(1);
}
output.write((const char *)default_right_icon, default_right_icon_len);
}
}
if (up_icon.empty()) {
up_icon = Filename("icons", default_up_icon_filename);
Filename icon_filename(archive_dir, up_icon);
if (force_regenerate || !icon_filename.exists()) {
nout << "Generating " << icon_filename << "\n";
icon_filename.make_dir();
icon_filename.set_binary();
ofstream output;
if (!icon_filename.open_write(output)) {
nout << "Unable to write to " << icon_filename << "\n";
exit(1);
}
output.write((const char *)default_up_icon, default_up_icon_len);
}
}
if (movie_icon.empty()) {
movie_icon = Filename("icons", default_movie_icon_filename);
Filename icon_filename(archive_dir, movie_icon);
if (force_regenerate || !icon_filename.exists()) {
nout << "Generating " << icon_filename << "\n";
icon_filename.make_dir();
icon_filename.set_binary();
ofstream output;
if (!icon_filename.open_write(output)) {
nout << "Unable to write to " << icon_filename << "\n";
exit(1);
}
output.write((const char *)default_movie_icon, default_movie_icon_len);
}
}
if (sound_icon.empty()) {
sound_icon = Filename("icons", default_sound_icon_filename);
Filename icon_filename(archive_dir, sound_icon);
if (force_regenerate || !icon_filename.exists()) {
nout << "Generating " << icon_filename << "\n";
icon_filename.make_dir();
icon_filename.set_binary();
ofstream output;
if (!icon_filename.open_write(output)) {
nout << "Unable to write to " << icon_filename << "\n";
exit(1);
}
output.write((const char *)default_sound_icon, default_sound_icon_len);
}
}
}
finalize_parameters();
return ProgramBase::post_command_line();
}
////////////////////////////////////////////////////////////////////
// Function: Indexify::dispatch_caption
// Access: Protected, Static
// Description: Dispatch function for the -caption parameter, which
// takes either one or two numbers separated by a comma,
// representing the caption font size and the optional
// pixel spacing of the caption under the image.
////////////////////////////////////////////////////////////////////
bool Indexify::
dispatch_caption(const string &opt, const string &arg, void *) {
vector_string words;
tokenize(arg, words, ",");
int caption_spacing = 0;
bool okflag = false;
if (words.size() == 1) {
okflag =
string_to_int(words[0], caption_font_size);
} else if (words.size() == 2) {
okflag =
string_to_int(words[0], caption_font_size) &&
string_to_int(words[1], caption_spacing);
}
if (!okflag) {
nout << "-" << opt
<< " requires one or two integers separated by a comma.\n";
return false;
}
thumb_caption_height = caption_font_size + caption_spacing;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: Indexify::run
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void Indexify::
run() {
bool all_ok = true;
RollDirs::iterator di;
for (di = _roll_dirs.begin(); di != _roll_dirs.end(); ++di) {
RollDirectory *roll_dir = (*di);
if (!roll_dir->scan(_photo_extension, _movie_extension, _sound_extension)) {
nout << "Unable to read " << *roll_dir << "\n";
all_ok = false;
}
roll_dir->collect_index_images();
}
if (!all_ok) {
exit(1);
}
if (_copy_reduced) {
do_copy_reduced();
} else {
do_generate_images();
}
}
////////////////////////////////////////////////////////////////////
// Function: Indexify::do_generate_images
// Access: Public
// Description: The main work function. Generates all of the reduced
// images and the html code.
////////////////////////////////////////////////////////////////////
void Indexify::
do_generate_images() {
// First, generate all the images.
RollDirs::iterator di;
for (di = _roll_dirs.begin(); di != _roll_dirs.end(); ++di) {
RollDirectory *roll_dir = (*di);
if (!roll_dir->generate_images(archive_dir, _text_maker)) {
nout << "Failure.\n";
exit(1);
}
}
// Then go back and generate the HTML.
for (di = _roll_dirs.begin(); di != _roll_dirs.end(); ++di) {
RollDirectory *roll_dir = (*di);
if (!roll_dir->generate_html(archive_dir, _roll_dir_root)) {
nout << "Failure.\n";
exit(1);
}
}
if (!omit_complete) {
// Generate the complete index that browses all the roll directories
// at once.
Filename complete_filename(archive_dir, "html/complete.htm");
nout << "Generating " << complete_filename << "\n";
complete_filename.set_text();
ofstream complete_html;
if (!complete_filename.open_write(complete_html)) {
nout << "Unable to write to " << complete_filename << "\n";
exit(1);
}
complete_html
<< "<html>\n"
<< "<head>\n"
<< "<title>" << _front_title << "</title>\n"
<< "</head>\n"
<< "<body>\n"
<< "<h1>" << _front_title << "</h1>\n";
for (di = _roll_dirs.begin(); di != _roll_dirs.end(); ++di) {
RollDirectory *roll_dir = (*di);
complete_html
<< roll_dir->get_comment_html()
<< roll_dir->get_index_html();
}
complete_html << "<p>\n";
if (!up_icon.empty()) {
// Use an icon to go up.
Filename up_icon_href = compose_href("..", up_icon);
complete_html
<< "<a href=\"../index.htm\"><img src=\"" << up_icon_href
<< "\" alt=\"return to index\"></a>\n";
} else {
// No up icon; use text to go up.
complete_html
<< "<br><a href=\"../index.htm\">Return to index</a>\n";
}
complete_html << "</p>\n";
complete_html
<< "</body>\n"
<< "</html>\n";
}
// And finally, generate the index HTML file that sits on the top of
// all of this.
Filename index_filename(archive_dir, "index.htm");
nout << "Generating " << index_filename << "\n";
index_filename.set_text();
ofstream index_html;
if (!index_filename.open_write(index_html)) {
nout << "Unable to write to " << index_filename << "\n";
exit(1);
}
index_html
<< "<html>\n"
<< "<head>\n"
<< "<title>" << _front_title << "</title>\n"
<< "</head>\n"
<< "<body>\n"
<< "<h1>" << _front_title << "</h1>\n"
<< "<ul>\n";
for (di = _roll_dirs.begin(); di != _roll_dirs.end(); ++di) {
RollDirectory *roll_dir = (*di);
if (!roll_dir->is_empty()) {
index_html
<< "<a name=\"" << roll_dir->get_basename() << "\">\n"
<< "<li><a href=\"html/" << roll_dir->get_basename() << ".htm\">"
<< roll_dir->get_name() << " " << escape_html(roll_dir->get_desc())
<< "</a></li>\n";
}
}
index_html
<< "</ul>\n";
if (!omit_complete) {
index_html
<< "<a href=\"html/complete.htm\">(complete archive)</a>\n";
}
index_html
<< "</body>\n"
<< "</html>\n";
}
////////////////////////////////////////////////////////////////////
// Function: Indexify::do_copy_reduced
// Access: Public
// Description: The main work function in -copyreduced mode. Simply
// copies key files from the full directory to the
// reduced directory.
////////////////////////////////////////////////////////////////////
void Indexify::
do_copy_reduced() {
RollDirs::iterator di;
for (di = _roll_dirs.begin(); di != _roll_dirs.end(); ++di) {
RollDirectory *roll_dir = (*di);
if (!roll_dir->copy_reduced(archive_dir)) {
nout << "Failure.\n";
exit(1);
}
}
}
int main(int argc, char *argv[]) {
Indexify prog;
prog.parse_command_line(argc, argv);
prog.run();
return 0;
}

View File

@ -1,66 +0,0 @@
// Filename: indexify.h
// Created by: drose (03Apr02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef INDEXIFY_H
#define INDEXIFY_H
#include "pandatoolbase.h"
#include "programBase.h"
#include "filename.h"
#include "pvector.h"
class RollDirectory;
class PNMTextMaker;
////////////////////////////////////////////////////////////////////
// Class : Indexify
// Description : A program to generate a series of thumbnail images
// and HTML pages to view a number of image files in an
// archive directory, before writing the archive to a
// permanent medium like a CD.
////////////////////////////////////////////////////////////////////
class Indexify : public ProgramBase {
public:
Indexify();
virtual ~Indexify();
protected:
virtual bool handle_args(Args &args);
virtual bool post_command_line();
static bool dispatch_caption(const string &opt, const string &arg, void *var);
public:
void run();
void do_generate_images();
void do_copy_reduced();
string _front_title;
Filename _roll_dir_root;
string _photo_extension;
string _movie_extension;
string _sound_extension;
Filename _font_filename;
bool _generate_icons;
double _font_aa_factor;
bool _copy_reduced;
typedef pvector<RollDirectory *> RollDirs;
RollDirs _roll_dirs;
PNMTextMaker *_text_maker;
};
#endif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 536 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 258 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -1,182 +0,0 @@
// Filename: photo.cxx
// Created by: drose (03Apr02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "photo.h"
#include "indexParameters.h"
#include "rollDirectory.h"
static const char * const standard_movie_extensions[] = {
"mov", "avi", "mpg", "mp4", NULL
};
static const char * const standard_sound_extensions[] = {
"mp3", "wav", "ogg", NULL
};
////////////////////////////////////////////////////////////////////
// Function: Photo::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
Photo::
Photo(RollDirectory *dir, const Filename &basename,
const string &movie_extension, const string &sound_extension) :
_dir(dir),
_basename(basename)
{
_name = _basename.get_basename_wo_extension();
_frame_number = _name;
if (caption_frame_numbers) {
const string &dirname = _dir->get_basename();
// If the initial prefix of the filename is the same as the roll
// directory, lop it off when caption_frame_numbers is in effect.
if (_frame_number.substr(0, dirname.length()) == dirname) {
_frame_number = _frame_number.substr(dirname.length());
while (_frame_number.length() > 1 && _frame_number[0] == '0') {
_frame_number = _frame_number.substr(1);
}
}
}
_full_x_size = 0;
_full_y_size = 0;
_reduced_x_size = 0;
_reduced_y_size = 0;
_has_reduced = false;
_has_movie = false;
Filename movie_filename(_dir->get_dir(), _basename);
movie_filename.set_extension(movie_extension);
if (movie_filename.exists()) {
_movie = movie_filename.get_basename();
_has_movie = true;
} else {
const char * const *ext;
for (ext = standard_movie_extensions; *ext != NULL; ++ext) {
movie_filename.set_extension(*ext);
if (movie_filename.exists()) {
_movie = movie_filename.get_basename();
_has_movie = true;
}
}
}
_has_sound = false;
Filename sound_filename(_dir->get_dir(), _basename);
sound_filename.set_extension(sound_extension);
if (sound_filename.exists()) {
_sound = sound_filename.get_basename();
_has_sound = true;
} else {
const char * const *ext;
for (ext = standard_sound_extensions; *ext != NULL; ++ext) {
sound_filename.set_extension(*ext);
if (sound_filename.exists()) {
_sound = sound_filename.get_basename();
_has_sound = true;
}
}
}
_has_cm = false;
Filename cm_filename(_dir->get_dir(), _basename);
cm_filename.set_extension("cm");
if (cm_filename.exists()) {
_cm = cm_filename.get_basename();
_has_cm = true;
}
}
////////////////////////////////////////////////////////////////////
// Function: Photo::get_basename
// Access: Public
// Description: Returns the filename of the photo within its roll
// directory.
////////////////////////////////////////////////////////////////////
const Filename &Photo::
get_basename() const {
return _basename;
}
////////////////////////////////////////////////////////////////////
// Function: Photo::get_movie
// Access: Public
// Description: Returns the filename of the movie associated with the
// photo, if any.
////////////////////////////////////////////////////////////////////
const Filename &Photo::
get_movie() const {
return _movie;
}
////////////////////////////////////////////////////////////////////
// Function: Photo::get_sound
// Access: Public
// Description: Returns the filename of the sound clip associated
// with the photo, if any.
////////////////////////////////////////////////////////////////////
const Filename &Photo::
get_sound() const {
return _sound;
}
////////////////////////////////////////////////////////////////////
// Function: Photo::get_cm
// Access: Public
// Description: Returns the filename of the comment file associated
// with the photo, if any.
////////////////////////////////////////////////////////////////////
const Filename &Photo::
get_cm() const {
return _cm;
}
////////////////////////////////////////////////////////////////////
// Function: Photo::get_name
// Access: Public
// Description: Returns the name of the photo without its filename
// extension.
////////////////////////////////////////////////////////////////////
const string &Photo::
get_name() const {
return _name;
}
////////////////////////////////////////////////////////////////////
// Function: Photo::get_frame_number
// Access: Public
// Description: Returns the string describing the photo within the
// roll directory. This is usually the same string
// reported by get_name(), but it may be just the frame
// number if caption_frame_numbers is in effect.
////////////////////////////////////////////////////////////////////
const string &Photo::
get_frame_number() const {
return _frame_number;
}
////////////////////////////////////////////////////////////////////
// Function: Photo::output
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void Photo::
output(ostream &out) const {
out << _basename;
}

View File

@ -1,67 +0,0 @@
// Filename: photo.h
// Created by: drose (03Apr02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef PHOTO_H
#define PHOTO_H
#include "pandatoolbase.h"
#include "filename.h"
class RollDirectory;
////////////////////////////////////////////////////////////////////
// Class : Photo
// Description : A single photo image within a roll directory.
////////////////////////////////////////////////////////////////////
class Photo {
public:
Photo(RollDirectory *dir, const Filename &basename,
const string &movie_extension, const string &sound_extension);
const Filename &get_basename() const;
const Filename &get_movie() const;
const Filename &get_sound() const;
const Filename &get_cm() const;
const string &get_name() const;
const string &get_frame_number() const;
void output(ostream &out) const;
public:
int _full_x_size;
int _full_y_size;
int _reduced_x_size;
int _reduced_y_size;
bool _has_reduced;
bool _has_movie;
bool _has_sound;
bool _has_cm;
private:
RollDirectory *_dir;
Filename _basename;
Filename _movie;
Filename _sound;
Filename _cm;
string _name;
string _frame_number;
};
INLINE ostream &operator << (ostream &out, const Photo &p) {
p.output(out);
return out;
}
#endif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 526 B

View File

@ -1,878 +0,0 @@
// Filename: rollDirectory.cxx
// Created by: drose (03Apr02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "rollDirectory.h"
#include "photo.h"
#include "indexImage.h"
#include "indent.h"
#include "pnotify.h"
#include "string_utils.h"
#include "indexParameters.h"
#include <ctype.h>
#include <algorithm>
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
RollDirectory::
RollDirectory(const Filename &dir) :
_dir(dir)
{
_prev = (RollDirectory *)NULL;
_next = (RollDirectory *)NULL;
_basename = _dir.get_basename();
if (format_rose) {
_name = format_basename(_basename);
} else {
_name = _basename;
}
_got_ds_file = false;
_got_ls_file = false;
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
RollDirectory::
~RollDirectory() {
IndexImages::iterator ii;
for (ii = _index_images.begin(); ii != _index_images.end(); ++ii) {
IndexImage *index_image = (*ii);
delete index_image;
}
Photos::iterator pi;
for (pi = _photos.begin(); pi != _photos.end(); ++pi) {
Photo *photo = (*pi);
delete photo;
}
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::get_dir
// Access: Public
// Description: Returns the filename of the directory.
////////////////////////////////////////////////////////////////////
const Filename &RollDirectory::
get_dir() const {
return _dir;
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::get_basename
// Access: Public
// Description: Returns the base name of the directory.
////////////////////////////////////////////////////////////////////
const string &RollDirectory::
get_basename() const {
return _basename;
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::get_name
// Access: Public
// Description: Returns the formatted name of the directory. This is
// often the same as the basename, but if -r is
// specified on the command line it might be a somewhat
// different, reformatted name. In any case, it is the
// name of the roll as it should be presented to the
// user.
////////////////////////////////////////////////////////////////////
const string &RollDirectory::
get_name() const {
return _name;
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::get_desc
// Access: Public
// Description: Returns the one-line description for the directory.
////////////////////////////////////////////////////////////////////
const string &RollDirectory::
get_desc() const {
return _desc;
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::scan
// Access: Public
// Description: Scans the directory for all the listed photos.
////////////////////////////////////////////////////////////////////
bool RollDirectory::
scan(const string &photo_extension, const string &movie_extension,
const string &sound_extension) {
bool reverse_order = false;
bool explicit_list = false;
// Check for a .ds file, which contains a one-line description of
// the contents of the directory.
_ds_filename = Filename(_basename);
_ds_filename.set_extension("ds");
if (cm_search.is_empty() || !_ds_filename.resolve_filename(cm_search)) {
// If the ds file isn't found along the search path specified
// via -cmdir on the command line, then look for it in the
// appropriate source directory.
_ds_filename = Filename(_dir, _ds_filename);
}
if (_ds_filename.exists()) {
_got_ds_file = true;
_ds_filename.set_text();
ifstream ds;
if (!_ds_filename.open_read(ds)) {
nout << "Could not read " << _ds_filename << "\n";
} else {
// Get the words out one at a time and put just one space
// between them.
string word;
ds >> word;
while (!ds.eof() && !ds.fail()) {
if (!_desc.empty()) {
_desc += ' ';
}
_desc += word;
word = string();
ds >> word;
}
if (!word.empty()) {
if (!_desc.empty()) {
_desc += ' ';
}
_desc += word;
}
}
}
// Check for an .ls file in the roll directory, which may give an
// explicit ordering, or if empty, it specifies reverse ordering.
_ls_filename = Filename(_dir, _basename);
_ls_filename.set_extension("ls");
if (_ls_filename.exists()) {
_got_ls_file = true;
add_contributing_filename(_ls_filename);
_ls_filename.set_text();
ifstream ls;
if (!_ls_filename.open_read(ls)) {
nout << "Could not read " << _ls_filename << "\n";
} else {
bool any_words = false;
string word;
ls >> word;
while (!ls.eof() && !ls.fail()) {
any_words = true;
Filename try_filename(_dir, word);
if (!try_filename.exists()) {
try_filename = Filename(_dir, word + "." + photo_extension);
}
if (!try_filename.exists()) {
try_filename = Filename(_dir, _basename + word + "." + photo_extension);
}
if (!try_filename.exists()) {
try_filename = Filename(_dir, _basename + "0" + word + "." + photo_extension);
}
if (try_filename.exists()) {
add_photo(try_filename.get_basename(), movie_extension,
sound_extension);
} else {
nout << "Frame " << word << " not found in " << _name << "\n";
}
ls >> word;
}
if (!any_words) {
// An empty .ls file just means reverse the order.
reverse_order = true;
} else {
// A non-empty .ls file has listed all the files we need; no
// need to scan the directory.
explicit_list = true;
}
}
}
if (!explicit_list) {
vector_string contents;
if (!_dir.scan_directory(contents)) {
nout << "Could not read " << _dir << "\n";
return false;
}
// We want to sort the filenames in our own way, so that
// underscore is deemed to fall before anything else. This allows
// the underscore, the only non-alphnumeric character we can have
// in a filename for an iso9660 image, to stand for "before 0".
sort(contents.begin(), contents.end(), compare_filenames);
if (reverse_order) {
reverse(contents.begin(), contents.end());
}
vector_string::iterator ci;
for (ci = contents.begin(); ci != contents.end(); ++ci) {
Filename basename = (*ci);
if (basename.get_extension() == photo_extension) {
add_photo(basename, movie_extension, sound_extension);
}
}
}
if (_photos.empty()) {
nout << _dir << " contains no photos.\n";
// This is not an error, just a notice.
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::collect_index_images
// Access: Public
// Description: Groups the photos into one or more IndexImages.
////////////////////////////////////////////////////////////////////
void RollDirectory::
collect_index_images() {
// Don't call this twice.
nassertv(_index_images.empty());
if (is_empty()) {
return;
}
IndexImage *index_image = new IndexImage(this, _index_images.size());
_index_images.push_back(index_image);
size_t i;
for (i = 0; i < _photos.size(); i++) {
if (!index_image->add_photo(i)) {
// Oops, that one's full.
index_image = new IndexImage(this, _index_images.size());
_index_images.push_back(index_image);
bool result = index_image->add_photo(i);
nassertv(result);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::sort_date_before
// Access: Public
// Description: Returns true if the given directory name should sort
// before the other one, assuming the Rose naming
// convention of mmyyss is in place.
////////////////////////////////////////////////////////////////////
bool RollDirectory::
sort_date_before(const RollDirectory &other) const {
if (_name == _basename && other._name == other._basename) {
// If Rose naming convention is not in place in either case, sort
// alphabetically.
return _basename < other._basename;
} else if (_name == _basename) {
// If Rose naming convention is in place on this one and not the
// other, it sorts first.
return true;
} else if (other._name == other._basename) {
// And vice-versa.
return false;
} else {
// Rose naming convention holds. Sort based on year first. Years
// above 90 are deemed to belong to the previous century.
string yy = _basename.substr(2, 2);
string other_yy = other._basename.substr(2, 2);
int year = atoi(yy.c_str());
int other_year = atoi(other_yy.c_str());
if (year < 90) {
year += 100;
}
if (other_year < 90) {
other_year += 100;
}
if (year != other_year) {
return year < other_year;
}
// After year, sort alphabetically.
return _basename < other._basename;
}
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::get_newest_contributing_filename
// Access: Public
// Description: Returns the Filename with the newest timestamp that
// contributes to the contents of the index images in
// this directory, if any (other than the images
// themselves). This is used by the IndexImage code to
// determine if it needs to regenerate the index image.
////////////////////////////////////////////////////////////////////
const Filename &RollDirectory::
get_newest_contributing_filename() const {
return _newest_contributing_filename;
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::is_empty
// Access: Public
// Description: Returns true if the directory is empty (has no
// photos).
////////////////////////////////////////////////////////////////////
bool RollDirectory::
is_empty() const {
return _photos.empty();
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::get_num_photos
// Access: Public
// Description: Returns the number of photos in the roll.
////////////////////////////////////////////////////////////////////
int RollDirectory::
get_num_photos() const {
return _photos.size();
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::get_photo
// Access: Public
// Description: Returns the nth photo in the roll.
////////////////////////////////////////////////////////////////////
Photo *RollDirectory::
get_photo(int n) const {
nassertr(n >= 0 && n < (int)_photos.size(), NULL);
return _photos[n];
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::get_num_index_images
// Access: Public
// Description: Returns the number of index images in the roll.
////////////////////////////////////////////////////////////////////
int RollDirectory::
get_num_index_images() const {
return _index_images.size();
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::get_index_image
// Access: Public
// Description: Returns the nth index image in the roll.
////////////////////////////////////////////////////////////////////
IndexImage *RollDirectory::
get_index_image(int n) const {
nassertr(n >= 0 && n < (int)_index_images.size(), NULL);
return _index_images[n];
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::generate_images
// Access: Public
// Description: Generates image files appropriate to this directory
// to the indicated archive dir. Returns true on
// success, false on failure.
////////////////////////////////////////////////////////////////////
bool RollDirectory::
generate_images(const Filename &archive_dir, PNMTextMaker *text_maker) {
if (is_empty()) {
return true;
}
nassertr(!_index_images.empty(), false);
IndexImages::iterator ii;
for (ii = _index_images.begin(); ii != _index_images.end(); ++ii) {
IndexImage *index_image = (*ii);
if (!index_image->generate_images(archive_dir, text_maker)) {
return false;
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::generate_html
// Access: Public
// Description: Generates all appropriate HTML files for this
// directory, and generate the appropriate HTML code
// into the html strings (retrieved by
// get_comment_html() and get_index_html()).
////////////////////////////////////////////////////////////////////
bool RollDirectory::
generate_html(const Filename &archive_dir, const Filename &roll_dir_root) {
if (is_empty()) {
return true;
}
nassertr(!_index_images.empty(), false);
ostringstream comment_strm;
comment_strm
<< "<a name=\"" << _basename << "\">\n";
if (!omit_roll_headers) {
Filename cm_filename(_basename);
cm_filename.set_extension("cm");
if (cm_search.is_empty() || !cm_filename.resolve_filename(cm_search)) {
// If the cm file isn't found along the search path specified
// via -cmdir on the command line, then look for it in the
// appropriate source directory.
cm_filename = Filename(_dir, cm_filename);
}
if (cm_filename.exists()) {
// If the comment file for the roll exists, insert its contents
// here instead of the generic header.
if (!insert_html_comment(comment_strm, cm_filename)) {
return false;
}
} else {
comment_strm
<< "<h2>" << _name << "</h2>\n";
if (!_desc.empty()) {
comment_strm << "<p>" << escape_html(_desc) << ".</p>\n";
}
}
}
_comment_html = comment_strm.str();
Filename html_dir(archive_dir, "html");
nout << "Generating " << Filename(html_dir, _basename) << "/*\n";
ostringstream index_strm;
index_strm << "<p>\n";
IndexImages::iterator ii;
for (ii = _index_images.begin(); ii != _index_images.end(); ++ii) {
IndexImage *index_image = (*ii);
if (!index_image->generate_html(index_strm, archive_dir, roll_dir_root)) {
return false;
}
}
index_strm << "</p>\n";
_index_html = index_strm.str();
// Also generate the index html for this directory.
Filename html_filename(html_dir, _basename);
html_filename.set_extension("htm");
nout << "Generating " << html_filename << "\n";
html_filename.set_text();
ofstream index_html;
if (!html_filename.open_write(index_html)) {
nout << "Unable to write to " << html_filename << "\n";
exit(1);
}
string up_href = "../index.htm#" + _basename;
Filename prev_roll_filename;
Filename next_roll_filename;
if (_prev != (RollDirectory *)NULL) {
prev_roll_filename = _prev->_basename;
prev_roll_filename.set_extension("htm");
}
if (_next != (RollDirectory *)NULL) {
next_roll_filename = _next->_basename;
next_roll_filename.set_extension("htm");
}
index_html
<< "<html>\n"
<< "<head>\n";
if (_desc.empty()) {
index_html
<< "<title>" << _name << "</title>\n";
} else {
index_html
<< "<title>" << _name << " " << escape_html(_desc) << "</title>\n";
}
index_html
<< "</head>\n"
<< "<body>\n"
<< get_comment_html();
generate_nav_buttons(index_html, prev_roll_filename, next_roll_filename,
up_href);
index_html << get_index_html();
generate_nav_buttons(index_html, prev_roll_filename, next_roll_filename,
up_href);
if (!omit_complete) {
index_html
<< "<a href=\"complete.htm#" << _basename
<< "\">(complete archive)</a>\n";
}
index_html
<< "</body>\n"
<< "</html>\n";
return true;
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::get_comment_html
// Access: Public
// Description: Returns the HTML text that describes this directory's
// index. This is set when generate_html() returns
// true.
//
// This text may be inserted into the middle of a HTML
// page to include the imagemap that references each of
// the images in this directory.
////////////////////////////////////////////////////////////////////
const string &RollDirectory::
get_comment_html() const {
return _comment_html;
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::get_index_html
// Access: Public
// Description: Returns the HTML text that describes this directory's
// index. This is set when generate_html() returns
// true.
//
// This text may be inserted into the middle of a HTML
// page to include the imagemap that references each of
// the images in this directory.
////////////////////////////////////////////////////////////////////
const string &RollDirectory::
get_index_html() const {
return _index_html;
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::copy_reduced
// Access: Public
// Description: Copies key files from the full directory into the
// reduced directory.
////////////////////////////////////////////////////////////////////
bool RollDirectory::
copy_reduced(const Filename &archive_dir) {
if (is_empty()) {
return true;
}
nassertr(!_index_images.empty(), false);
Filename reduced_dir(archive_dir, "reduced/" + _dir.get_basename());
if (!reduced_dir.exists()) {
cerr << "Ignoring " << reduced_dir << "; does not exist.\n";
return true;
}
if (_got_ds_file) {
if (!copy_file(_ds_filename, reduced_dir)) {
return false;
}
}
if (_got_ls_file) {
if (!copy_file(_ls_filename, reduced_dir)) {
return false;
}
}
IndexImages::iterator ii;
for (ii = _index_images.begin(); ii != _index_images.end(); ++ii) {
IndexImage *index_image = (*ii);
if (!index_image->copy_reduced(archive_dir)) {
return false;
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::output
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void RollDirectory::
output(ostream &out) const {
out << _name;
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::write
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void RollDirectory::
write(ostream &out, int indent_level) const {
indent(out, indent_level)
<< _dir << "\n";
if (!_index_images.empty()) {
// If we have any index images, output those.
IndexImages::const_iterator ii;
for (ii = _index_images.begin(); ii != _index_images.end(); ++ii) {
const IndexImage *index_image = (*ii);
index_image->write(out, indent_level + 2);
}
} else {
// Otherwise, just output the photos.
Photos::const_iterator pi;
for (pi = _photos.begin(); pi != _photos.end(); ++pi) {
const Photo *photo = (*pi);
indent(out, indent_level + 2)
<< *photo << "\n";
}
}
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::insert_html_comment
// Access: Public, Static
// Description: Reads the indicated comment file and inserts its
// contents (after the header) within the indicated
// ostream at the current point.
////////////////////////////////////////////////////////////////////
bool RollDirectory::
insert_html_comment(ostream &html, Filename cm_filename) {
cm_filename.set_text();
ifstream cm;
if (!cm_filename.open_read(cm)) {
nout << "Unable to read " << cm_filename << "\n";
return false;
}
// First, scan through the file looking for <BODY> or <body>.
string line;
getline(cm, line);
while (!cm.eof() && !cm.fail()) {
string lower = downcase(line);
size_t body = lower.find("<body>");
if (body != string::npos) {
return insert_html_comment_body(html, cm);
}
getline(cm, line);
}
// We didn't find it. Insert the whole file.
cm.clear();
cm.seekg(0);
int ch = cm.get();
while (ch != EOF) {
html.put(ch);
ch = cm.get();
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::add_photo
// Access: Private
// Description: Adds the photo with the indicated basename to the
// list.
////////////////////////////////////////////////////////////////////
void RollDirectory::
add_photo(const Filename &basename, const string &movie_extension,
const string &sound_extension) {
Photo *photo = new Photo(this, basename, movie_extension, sound_extension);
_photos.push_back(photo);
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::add_contributing_filename
// Access: Private
// Description: Specifies an additional filename that contributes to
// the index image.
////////////////////////////////////////////////////////////////////
void RollDirectory::
add_contributing_filename(const Filename &filename) {
if (_newest_contributing_filename.empty() ||
_newest_contributing_filename.compare_timestamps(filename) < 0) {
_newest_contributing_filename = filename;
}
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::insert_html_comment_body
// Access: Private, Static
// Description: Copies from the comment file up until the next
// </body>, or until the end of file.
////////////////////////////////////////////////////////////////////
bool RollDirectory::
insert_html_comment_body(ostream &html, istream &cm) {
string line;
getline(cm, line);
while (!cm.eof() && !cm.fail()) {
string lower = downcase(line);
size_t body = lower.find("</body>");
if (body != string::npos) {
// Here's the end; we're done.
return true;
}
html << line << "\n";
getline(cm, line);
}
// Reached end of file; good enough.
return true;
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::format_basename
// Access: Private, Static
// Description: Reformats the roll directory into a user-friendly
// name based on its encoded directory name.
////////////////////////////////////////////////////////////////////
string RollDirectory::
format_basename(const string &basename) {
if (basename.length() <= 4) {
return basename;
}
// The first two characters must be alphanumeric.
if (!isalnum(basename[0]) || !isalnum(basename[1])) {
return basename;
}
// The next two characters must be digits.
if (!isdigit(basename[2]) || !isdigit(basename[3])) {
return basename;
}
// If the first two were digits as well as being alphanumeric, then
// we have mm-yy/sequence. Otherwise, we just have xxyy/sequence.
bool mm_is_month = (isdigit(basename[0]) && isdigit(basename[1]));
string mm = basename.substr(0, 2);
string yy = basename.substr(2, 2);
string ss = basename.substr(4);
if (mm_is_month && mm[0] == '0') {
mm = mm[1];
}
while (ss.length() > 1 && ss[0] == '0') {
ss = ss.substr(1);
}
if (mm_is_month) {
return mm + "-" + yy + "/" + ss;
} else {
return mm + yy + "/" + ss;
}
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::generate_nav_buttons
// Access: Private, Static
// Description: Outputs the HTML code to generate the next, prev,
// up buttons when viewing each reduced image.
////////////////////////////////////////////////////////////////////
void RollDirectory::
generate_nav_buttons(ostream &html, const Filename &prev_roll_filename,
const Filename &next_roll_filename,
const string &up_href) {
html << "<p>\n";
bool first_icons = false;
if (!prev_icon.empty() && !next_icon.empty()) {
first_icons = true;
// Use icons to go forward and back.
Filename prev_icon_href = compose_href("..", prev_icon);
if (prev_roll_filename.empty()) {
html << "<img src=\"" << prev_icon_href << "\" alt=\"No previous roll\">\n";
} else {
html << "<a href=\"" << prev_roll_filename
<< "\"><img src=\"" << prev_icon_href << "\" alt=\"previous\"></a>\n";
}
Filename next_icon_href = compose_href("..", next_icon);
if (next_roll_filename.empty()) {
html << "<img src=\"" << next_icon_href << "\" alt=\"No next roll\">\n";
} else {
html << "<a href=\"" << next_roll_filename
<< "\"><img src=\"" << next_icon_href << "\" alt=\"next\"></a>\n";
}
} else {
// No prev/next icons; use text to go forward and back.
if (prev_roll_filename.empty()) {
html << "(This is the first roll.)\n";
} else {
html << "<a href=\"" << prev_roll_filename
<< "\">Back to previous roll</a>\n";
}
if (next_roll_filename.empty()) {
html << "<br>(This is the last roll.)\n";
} else {
html << "<br><a href=\"" << next_roll_filename
<< "\">On to next roll</a>\n";
}
}
if (!up_href.empty()) {
if (!up_icon.empty()) {
// Use an icon to go up.
if (!first_icons) {
html << "<br>";
} else {
html << "&nbsp;&nbsp;&nbsp;";
}
Filename up_icon_href = compose_href("..", up_icon);
html << "<a href=\"" << up_href
<< "\"><img src=\"" << up_icon_href << "\" alt=\"return to index\"></a>\n";
} else {
// No up icon; use text to go up.
html << "<br><a href=\"" << up_href
<< "\">Return to index</a>\n";
}
}
html << "</p>\n";
}
////////////////////////////////////////////////////////////////////
// Function: RollDirectory::compare_filenames
// Access: Private, Static
// Description: Returns true if filename a sorts before filename b,
// false otherwise.
////////////////////////////////////////////////////////////////////
bool RollDirectory::
compare_filenames(const string &a, const string &b) {
size_t i = 0;
size_t min_length = min(a.length(), b.length());
while (i < min_length) {
char achar = a[i];
char bchar = b[i];
if (achar != bchar) {
if (achar == '_') {
return true;
} else if (bchar == '_') {
return false;
} else {
return achar < bchar;
}
}
++i;
}
return a.length() < b.length();
}

View File

@ -1,112 +0,0 @@
// Filename: rollDirectory.h
// Created by: drose (03Apr02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef ROLLDIRECTORY_H
#define ROLLDIRECTORY_H
#include "pandatoolbase.h"
#include "filename.h"
#include "pvector.h"
class Photo;
class IndexImage;
class PNMTextMaker;
////////////////////////////////////////////////////////////////////
// Class : RollDirectory
// Description : A representation of a single directory containing one
// or more photos.
////////////////////////////////////////////////////////////////////
class RollDirectory {
public:
RollDirectory(const Filename &dir);
~RollDirectory();
const Filename &get_dir() const;
const string &get_basename() const;
const string &get_name() const;
const string &get_desc() const;
bool scan(const string &photo_extension, const string &movie_extension,
const string &sound_extension);
void collect_index_images();
bool sort_date_before(const RollDirectory &other) const;
const Filename &get_newest_contributing_filename() const;
bool is_empty() const;
int get_num_photos() const;
Photo *get_photo(int n) const;
int get_num_index_images() const;
IndexImage *get_index_image(int n) const;
bool generate_images(const Filename &archive_dir, PNMTextMaker *text_maker);
bool generate_html(const Filename &archive_dir,
const Filename &roll_dir_root);
const string &get_comment_html() const;
const string &get_index_html() const;
bool copy_reduced(const Filename &archive_dir);
void output(ostream &out) const;
void write(ostream &out, int indent_level) const;
static bool insert_html_comment(ostream &html, Filename cm_filename);
private:
void add_photo(const Filename &basename, const string &movie_extension,
const string &sound_extension);
void add_contributing_filename(const Filename &filename);
static bool insert_html_comment_body(ostream &html, istream &cm);
static string format_basename(const string &basename);
void generate_nav_buttons(ostream &html,
const Filename &prev_roll_filename,
const Filename &next_roll_filename,
const string &up_href);
static bool compare_filenames(const string &a, const string &b);
public:
RollDirectory *_prev;
RollDirectory *_next;
private:
Filename _dir;
string _basename;
string _name;
string _desc;
typedef pvector<Photo *> Photos;
Photos _photos;
bool _got_ds_file;
Filename _ds_filename;
bool _got_ls_file;
Filename _ls_filename;
Filename _newest_contributing_filename;
typedef pvector<IndexImage *> IndexImages;
IndexImages _index_images;
string _comment_html;
string _index_html;
};
INLINE ostream &operator << (ostream &out, const RollDirectory &d) {
d.output(out);
return out;
}
#endif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 310 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 549 B

View File

@ -1,10 +0,0 @@
#begin ss_lib_target
#define TARGET pandaappbase
#define SOURCES \
pandaappbase.cxx pandaappbase.h pandaappsymbols.h
#define INSTALL_HEADERS \
pandaappbase.h pandaappsymbols.h
#end ss_lib_target

View File

@ -1,15 +0,0 @@
// Filename: pandaappbase.cxx
// Created by: drose (15Sep00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "pandaappbase.h"

View File

@ -1,25 +0,0 @@
// Filename: pandaappbase.h
// Created by: drose (12Sep00)
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
/* This file is included at the beginning of every header file and/or
C or C++ file. It must be compilable for C as well as C++ files,
so no C++-specific code or syntax can be put here. */
#ifndef PANDAAPPBASE_H
#define PANDAAPPBASE_H
#include "pandatoolbase.h"
#include "pandaappsymbols.h"
#endif

View File

@ -1,26 +0,0 @@
/* Filename: pandaappsymbols.h
* Created by: drose (26Apr01)
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef PANDAAPPSYMBOLS_H
#define PANDAAPPSYMBOLS_H
/* See dtoolsymbols.h for a rant on the purpose of this file. */
#if defined(WIN32_VC) && !defined(CPPPARSER) && !defined(LINK_ALL_STATIC)
#else /* !WIN32_VC */
#endif /* WIN32_VC */
#endif