NITRO uses an algorithmic coding style that is based on object-oriented languages, particularly Java. This style reflects into each language binding that exists for the library. Each public object in the NITRO API has the namespace 'nitf.' In languages that support namespaces, the nitf namespace is presented as expected. In languages that do not (namely C), the namespace is delimited using an underscore.
* \struct nitf_DLL
* \brief The C structure for loading a DLL
typedef struct _nitf_DLL
char *libname; /* The name of the library */
NITF_NATIVE_DLL lib; /* A handle to the library */
NITRO is object-oriented, though its core component is developed in a procedural language (C). Methods in the C core are delineated by the namespace, followed by the class name, and then the method name (all delineated with an underscore). The package name (nitf), is always lowercase, and the class name always uses camel case, beginning with a capital letter. The fields and members always begin with a lower case letter (and are camel case as well).
* Construct a DLL object
* This does nothing more than a memset, and a ZERO,
* and then it returns the object
* \param error An error object to fill on problem
* \return A DLL object, or NULL upon failure
NITFAPI(nitf_DLL *) nitf_DLL_construct(nitf_Error * error);
All objects that are publicly scoped must be declared using the NITFAPI() macro surrounding the return value. Package protected methods can be declared NITFPROT() in which case, they should have declarations in the header file, and definitions in the C file. Private methods are 'static' and should only be declared in the C code.
Since C does not have exceptions, errors in C are propagated using the nitf_Error object. For the most part, all functions that do not return pointers, should return NITF_SUCCESS or NITF_FAILURE, and should take in an nitf_Error as the final argument (an output parameter).
This is typically done in the library a goto sequence similar to a try/catch block:
/* Read from the IO handle */
success = nitf_IOHandle_read(reader->inputHandle, fld, length, error);
"Unable to read from IO object",
/* Handle any errors */
All classes should have three lifecycle operations. First, all classes should have a constructor -- nitf_XXXX_construct, which takes, as a final parameter, an error. The constructor should return a malloc'ed pointer an instance of that class.
All public and protected member functions must take the object as the first argument (explicit 'this'), whether or not it is used. 'Static' methods may also be used -- functions that do not require the object to be instantiated. In that case, the function will obviously not require a pointer to an instance of the class:
NITFAPI(NITF_BOOL) nitf_PluginRegistry_loadDir(const char* dirName, nitf_Error * error);
Macros are not always publicly exposed. If a macro is useful within a C file, it should, most often, be defined there in the C file. If it is defined in the header, it should have utility elsewhere in the library and be publicly useful (i.e., to the application developer). Macros and typedefs are capitalized, delimited by underscores. Macros are used in the library to reduce monotonous code, where useful. However, we try not to expose these macros to the users.
All C library code must be documented using Doxygen comments in the header. Java code must be documented using JavaDoc
Platform Specific Behavior
We try to localize all platform specific behavior into separate source files...